diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 08a2f40bbf5243..40256277702074 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 13 #define V8_MINOR_VERSION 7 #define V8_BUILD_NUMBER 152 -#define V8_PATCH_LEVEL 14 +#define V8_PATCH_LEVEL 19 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 526eb368c43ece..33abb93ea8e27c 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -3875,7 +3875,7 @@ void Isolate::SwitchStacks(wasm::StackMemory* from, wasm::StackMemory* to) { // TODO(388533754): This check won't hold anymore with core stack-switching. // Instead, we will need to validate all the intermediate stacks and also // check that they don't hold central stack frames. - DCHECK_EQ(from->jmpbuf()->parent, to); + SBXCHECK_EQ(from->jmpbuf()->parent, to); } uintptr_t limit = reinterpret_cast(to->jmpbuf()->stack_limit); stack_guard()->SetStackLimitForStackSwitching(limit); diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 9c24e1e8417b94..f43b693dadc238 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -1221,7 +1221,8 @@ class V8_NODISCARD BytecodeGenerator::OptionalChainNullLabelScope final { public: explicit OptionalChainNullLabelScope(BytecodeGenerator* bytecode_generator) : bytecode_generator_(bytecode_generator), - labels_(bytecode_generator->zone()) { + labels_(bytecode_generator->zone()), + hole_check_scope_(bytecode_generator) { prev_ = bytecode_generator_->optional_chaining_null_labels_; bytecode_generator_->optional_chaining_null_labels_ = &labels_; } @@ -1236,6 +1237,9 @@ class V8_NODISCARD BytecodeGenerator::OptionalChainNullLabelScope final { BytecodeGenerator* bytecode_generator_; BytecodeLabels labels_; BytecodeLabels* prev_; + // Use the same scope for the entire optional chain, as links earlier in the + // chain dominate later links, linearly. + HoleCheckElisionScope hole_check_scope_; }; // LoopScope delimits the scope of {loop}, from its header to its final jump. @@ -6461,9 +6465,6 @@ template void BytecodeGenerator::BuildOptionalChain(ExpressionFunc expression_func) { BytecodeLabel done; OptionalChainNullLabelScope label_scope(this); - // Use the same scope for the entire optional chain, as links earlier in the - // chain dominate later links, linearly. - HoleCheckElisionScope elider(this); expression_func(); builder()->Jump(&done); label_scope.labels()->Bind(builder()); diff --git a/deps/v8/src/objects/js-break-iterator.cc b/deps/v8/src/objects/js-break-iterator.cc index 0071e757352e7f..ee4d7ccad9e3e7 100644 --- a/deps/v8/src/objects/js-break-iterator.cc +++ b/deps/v8/src/objects/js-break-iterator.cc @@ -43,13 +43,12 @@ MaybeDirectHandle JSV8BreakIterator::New( MAYBE_RETURN(maybe_locale_matcher, MaybeDirectHandle()); Intl::MatcherOption matcher = maybe_locale_matcher.FromJust(); - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSV8BreakIterator::GetAvailableLocales(), - requested_locales, matcher, {}); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSV8BreakIterator::GetAvailableLocales(), + requested_locales, matcher, {}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); // Extract type from options enum class Type { CHARACTER, WORD, SENTENCE, LINE }; diff --git a/deps/v8/src/objects/js-collator.cc b/deps/v8/src/objects/js-collator.cc index 405cad15521c74..680252764535f0 100644 --- a/deps/v8/src/objects/js-collator.cc +++ b/deps/v8/src/objects/js-collator.cc @@ -357,18 +357,16 @@ MaybeHandle JSCollator::New(Isolate* isolate, DirectHandle map, // https://tc39.github.io/ecma402/#sec-intl-collator-internal-slots // // 16. Let relevantExtensionKeys be %Collator%.[[RelevantExtensionKeys]]. - std::set relevant_extension_keys{"co", "kn", "kf"}; // 17. Let r be ResolveLocale(%Collator%.[[AvailableLocales]], // requestedLocales, opt, %Collator%.[[RelevantExtensionKeys]], // localeData). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSCollator::GetAvailableLocales(), - requested_locales, matcher, relevant_extension_keys); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSCollator::GetAvailableLocales(), + requested_locales, matcher, {"co", "kn", "kf"}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); // 18. Set collator.[[Locale]] to r.[[locale]]. icu::Locale icu_locale = r.icu_locale; diff --git a/deps/v8/src/objects/js-date-time-format.cc b/deps/v8/src/objects/js-date-time-format.cc index b4d2a56931f25c..f74f733e6f07f3 100644 --- a/deps/v8/src/objects/js-date-time-format.cc +++ b/deps/v8/src/objects/js-date-time-format.cc @@ -2249,20 +2249,19 @@ MaybeDirectHandle JSDateTimeFormat::CreateDateTimeFormat( // ecma402/#sec-intl.datetimeformat-internal-slots // The value of the [[RelevantExtensionKeys]] internal slot is // « "ca", "nu", "hc" ». - std::set relevant_extension_keys = {"nu", "ca", "hc"}; // 10. Let localeData be %DateTimeFormat%.[[LocaleData]]. // 11. Let r be ResolveLocale( %DateTimeFormat%.[[AvailableLocales]], // requestedLocales, opt, %DateTimeFormat%.[[RelevantExtensionKeys]], // localeData). // - Maybe maybe_resolve_locale = Intl::ResolveLocale( - isolate, JSDateTimeFormat::GetAvailableLocales(), requested_locales, - locale_matcher, relevant_extension_keys); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSDateTimeFormat::GetAvailableLocales(), + requested_locales, locale_matcher, + {"nu", "ca", "hc"}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); icu::Locale icu_locale = r.icu_locale; DCHECK(!icu_locale.isBogus()); diff --git a/deps/v8/src/objects/js-display-names.cc b/deps/v8/src/objects/js-display-names.cc index e95a4c6c985a3f..9af8a6868ded05 100644 --- a/deps/v8/src/objects/js-display-names.cc +++ b/deps/v8/src/objects/js-display-names.cc @@ -436,16 +436,14 @@ MaybeDirectHandle JSDisplayNames::New( // ecma402/#sec-Intl.DisplayNames-internal-slots // The value of the [[RelevantExtensionKeys]] internal slot is // « ». - std::set relevant_extension_keys = {}; // 9. Let r be ResolveLocale(%DisplayNames%.[[AvailableLocales]], // requestedLocales, opt, %DisplayNames%.[[RelevantExtensionKeys]]). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSDisplayNames::GetAvailableLocales(), - requested_locales, matcher, relevant_extension_keys); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSDisplayNames::GetAvailableLocales(), + requested_locales, matcher, {}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); icu::Locale icu_locale = r.icu_locale; diff --git a/deps/v8/src/objects/js-duration-format.cc b/deps/v8/src/objects/js-duration-format.cc index 4524d71def3176..69ac5b8f82abba 100644 --- a/deps/v8/src/objects/js-duration-format.cc +++ b/deps/v8/src/objects/js-duration-format.cc @@ -289,13 +289,12 @@ MaybeDirectHandle JSDurationFormat::New( // 9. Let r be ResolveLocale(%DurationFormat%.[[AvailableLocales]], // requestedLocales, opt, %DurationFormat%.[[RelevantExtensionKeys]], // %DurationFormat%.[[LocaleData]]). - std::set relevant_extension_keys{"nu"}; Intl::ResolvedLocale r; - MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE( - isolate, r, - Intl::ResolveLocale(isolate, JSDurationFormat::GetAvailableLocales(), - requested_locales, matcher, relevant_extension_keys), - DirectHandle()); + if (!Intl::ResolveLocale(isolate, JSDurationFormat::GetAvailableLocales(), + requested_locales, matcher, {"nu"}) + .To(&r)) { + THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); + } // 10. Let locale be r.[[locale]]. icu::Locale r_locale = r.icu_locale; diff --git a/deps/v8/src/objects/js-list-format.cc b/deps/v8/src/objects/js-list-format.cc index 97a0f6a8f5162b..40be1c5e111b30 100644 --- a/deps/v8/src/objects/js-list-format.cc +++ b/deps/v8/src/objects/js-list-format.cc @@ -87,13 +87,13 @@ MaybeDirectHandle JSListFormat::New( // 10. Let r be ResolveLocale(%ListFormat%.[[AvailableLocales]], // requestedLocales, opt, undefined, localeData). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSListFormat::GetAvailableLocales(), - requested_locales, matcher, {}); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSListFormat::GetAvailableLocales(), + requested_locales, matcher, {}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); + DirectHandle locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); diff --git a/deps/v8/src/objects/js-number-format.cc b/deps/v8/src/objects/js-number-format.cc index 721d428af135b2..734cf647d61dac 100644 --- a/deps/v8/src/objects/js-number-format.cc +++ b/deps/v8/src/objects/js-number-format.cc @@ -1108,14 +1108,12 @@ MaybeDirectHandle JSNumberFormat::New( // 10. Let r be ResolveLocale(%NumberFormat%.[[AvailableLocales]], // requestedLocales, opt, %NumberFormat%.[[RelevantExtensionKeys]], // localeData). - std::set relevant_extension_keys{"nu"}; - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSNumberFormat::GetAvailableLocales(), - requested_locales, matcher, relevant_extension_keys); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSNumberFormat::GetAvailableLocales(), + requested_locales, matcher, {"nu"}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); icu::Locale icu_locale = r.icu_locale; UErrorCode status = U_ZERO_ERROR; diff --git a/deps/v8/src/objects/js-plural-rules.cc b/deps/v8/src/objects/js-plural-rules.cc index 4606b75f422cd4..a0cc5c7ea015e6 100644 --- a/deps/v8/src/objects/js-plural-rules.cc +++ b/deps/v8/src/objects/js-plural-rules.cc @@ -107,13 +107,12 @@ MaybeDirectHandle JSPluralRules::New( // 11. Let r be ResolveLocale(%PluralRules%.[[AvailableLocales]], // requestedLocales, opt, %PluralRules%.[[RelevantExtensionKeys]], // localeData). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSPluralRules::GetAvailableLocales(), - requested_locales, matcher, {}); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSPluralRules::GetAvailableLocales(), + requested_locales, matcher, {}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); DirectHandle locale_str = isolate->factory()->NewStringFromAsciiChecked(r.locale.c_str()); diff --git a/deps/v8/src/objects/js-regexp.cc b/deps/v8/src/objects/js-regexp.cc index ddd3923460f63e..d48cda043663ee 100644 --- a/deps/v8/src/objects/js-regexp.cc +++ b/deps/v8/src/objects/js-regexp.cc @@ -190,10 +190,14 @@ bool IsLineTerminator(int c) { // WriteEscapedRegExpSource into a single function to deduplicate dispatch logic // and move related code closer to each other. template -int CountAdditionalEscapeChars(DirectHandle source, - bool* needs_escapes_out) { +uint32_t CountAdditionalEscapeChars(DirectHandle source, + bool* needs_escapes_out) { DisallowGarbageCollection no_gc; - int escapes = 0; + uint32_t escapes = 0; + // The maximum growth-factor is 5 (for \u2028 and \u2029). Make sure that we + // won't overflow |escapes| given the current constraints on string length. + static_assert(uint64_t{String::kMaxLength} * 5 < + std::numeric_limits::max()); bool needs_escapes = false; bool in_character_class = false; base::Vector src = source->GetCharVector(no_gc); @@ -232,14 +236,14 @@ int CountAdditionalEscapeChars(DirectHandle source, } } DCHECK(!in_character_class); - DCHECK_GE(escapes, 0); DCHECK_IMPLIES(escapes != 0, needs_escapes); *needs_escapes_out = needs_escapes; return escapes; } template -void WriteStringToCharVector(base::Vector v, int* d, const char* string) { +void WriteStringToCharVector(base::Vector v, uint32_t* d, + const char* string) { int s = 0; while (string[s] != '\0') v[(*d)++] = string[s++]; } @@ -250,13 +254,13 @@ DirectHandle WriteEscapedRegExpSource( DisallowGarbageCollection no_gc; base::Vector src = source->GetCharVector(no_gc); base::Vector dst(result->GetChars(no_gc), result->length()); - int s = 0; - int d = 0; + uint32_t s = 0; + uint32_t d = 0; bool in_character_class = false; - while (s < src.length()) { + while (s < src.size()) { const Char c = src[s]; if (c == '\\') { - if (s + 1 < src.length() && IsLineTerminator(src[s + 1])) { + if (s + 1 < src.size() && IsLineTerminator(src[s + 1])) { // This '\' is ignored since the next character itself will be escaped. s++; continue; @@ -264,7 +268,7 @@ DirectHandle WriteEscapedRegExpSource( // Escape. Copy this and next character. dst[d++] = src[s++]; } - if (s == src.length()) break; + if (s == src.size()) break; } else if (c == '/' && !in_character_class) { // Not escaped forward-slash needs escape. dst[d++] = '\\'; @@ -304,11 +308,13 @@ MaybeDirectHandle EscapeRegExpSource(Isolate* isolate, if (source->length() == 0) return isolate->factory()->query_colon_string(); bool one_byte = String::IsOneByteRepresentationUnderneath(*source); bool needs_escapes = false; - int additional_escape_chars = + uint32_t additional_escape_chars = one_byte ? CountAdditionalEscapeChars(source, &needs_escapes) : CountAdditionalEscapeChars(source, &needs_escapes); if (!needs_escapes) return source; - int length = source->length() + additional_escape_chars; + DCHECK_LE(static_cast(source->length()) + additional_escape_chars, + std::numeric_limits::max()); + uint32_t length = source->length() + additional_escape_chars; if (one_byte) { DirectHandle result; ASSIGN_RETURN_ON_EXCEPTION(isolate, result, diff --git a/deps/v8/src/objects/js-relative-time-format.cc b/deps/v8/src/objects/js-relative-time-format.cc index 22fe8ec2d44485..58080f89ed9974 100644 --- a/deps/v8/src/objects/js-relative-time-format.cc +++ b/deps/v8/src/objects/js-relative-time-format.cc @@ -110,13 +110,12 @@ MaybeDirectHandle JSRelativeTimeFormat::New( // ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], // requestedLocales, opt, // %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSRelativeTimeFormat::GetAvailableLocales(), - requested_locales, matcher, {"nu"}); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSRelativeTimeFormat::GetAvailableLocales(), + requested_locales, matcher, {"nu"}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); UErrorCode status = U_ZERO_ERROR; diff --git a/deps/v8/src/objects/js-segmenter.cc b/deps/v8/src/objects/js-segmenter.cc index 0bd4a5eb222692..90e835a48f2e1a 100644 --- a/deps/v8/src/objects/js-segmenter.cc +++ b/deps/v8/src/objects/js-segmenter.cc @@ -53,13 +53,12 @@ MaybeDirectHandle JSSegmenter::New( // 11. Let r be ResolveLocale(%Segmenter%.[[AvailableLocales]], // requestedLocales, opt, %Segmenter%.[[RelevantExtensionKeys]]). - Maybe maybe_resolve_locale = - Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(), - requested_locales, matcher, {}); - if (maybe_resolve_locale.IsNothing()) { + Intl::ResolvedLocale r; + if (!Intl::ResolveLocale(isolate, JSSegmenter::GetAvailableLocales(), + requested_locales, matcher, {}) + .To(&r)) { THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kIcuError)); } - Intl::ResolvedLocale r = maybe_resolve_locale.FromJust(); // 12. Set segmenter.[[Locale]] to the value of r.[[locale]]. DirectHandle locale_str = diff --git a/deps/v8/src/wasm/baseline/liftoff-assembler.cc b/deps/v8/src/wasm/baseline/liftoff-assembler.cc index 47b4ddc36ebcf2..4387e7490740a6 100644 --- a/deps/v8/src/wasm/baseline/liftoff-assembler.cc +++ b/deps/v8/src/wasm/baseline/liftoff-assembler.cc @@ -884,6 +884,13 @@ void LiftoffAssembler::FinishCall(const ValueKindSig* sig, DCHECK(!loc.IsAnyRegister()); reg_pair[pair_idx] = LiftoffRegister::from_external_code( rc, lowered_kind, loc.AsRegister()); +#if V8_TARGET_ARCH_64_BIT + // See explanation in `LiftoffCompiler::ParameterProcessor`. + if (return_kind == kI32) { + DCHECK(!needs_gp_pair); + clear_i32_upper_half(reg_pair[0].gp()); + } +#endif } else { DCHECK(loc.IsCallerFrameSlot()); reg_pair[pair_idx] = GetUnusedRegister(rc, pinned); diff --git a/deps/v8/src/wasm/baseline/liftoff-compiler.cc b/deps/v8/src/wasm/baseline/liftoff-compiler.cc index 0e9dc6d4c05b91..8aed8bbaf5b186 100644 --- a/deps/v8/src/wasm/baseline/liftoff-compiler.cc +++ b/deps/v8/src/wasm/baseline/liftoff-compiler.cc @@ -9218,6 +9218,7 @@ class LiftoffCompiler { if (v8_flags.experimental_wasm_skip_null_checks || !type.is_nullable()) { return; } + SCOPED_CODE_COMMENT("null check"); LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned); LoadNullValueForCompare(null.gp(), pinned, type); OolTrapLabel trap = @@ -9230,6 +9231,7 @@ class LiftoffCompiler { LiftoffRegister array, LiftoffRegister index, LiftoffRegList pinned) { if (V8_UNLIKELY(v8_flags.experimental_wasm_skip_bounds_checks)) return; + SCOPED_CODE_COMMENT("array bounds check"); LiftoffRegister length = __ GetUnusedRegister(kGpReg, pinned); constexpr int kLengthOffset = wasm::ObjectAccess::ToTagged(WasmArray::kLengthOffset); diff --git a/deps/v8/test/intl/regress-412149700.js b/deps/v8/test/intl/regress-412149700.js new file mode 100644 index 00000000000000..f355a913ecc491 --- /dev/null +++ b/deps/v8/test/intl/regress-412149700.js @@ -0,0 +1,22 @@ +// Copyright 2025 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +assertThrows("let a = new Intl.DateTimeFormat('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.NumberFormat('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.Collator('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.PluralRules('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.RelativeTimeFormat('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.ListFormat('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.DisplayNames('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.Segmenter('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); +assertThrows("let a = new Intl.DurationFormat('de-u-22300-true-x-true')", + RangeError, "Internal error. Icu error."); diff --git a/deps/v8/test/mjsunit/sandbox/liftoff-wasmarray-i64-indexing.js b/deps/v8/test/mjsunit/sandbox/liftoff-wasmarray-i64-indexing.js new file mode 100644 index 00000000000000..a34ff401d050b3 --- /dev/null +++ b/deps/v8/test/mjsunit/sandbox/liftoff-wasmarray-i64-indexing.js @@ -0,0 +1,108 @@ +// Copyright 2025 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-memory-corruption-api + +d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js'); + +// Prepare corruption utilities. +const kHeapObjectTag = 1; +const kWasmGlobalObjectTaggedBufferOffset = 0x14; +const kFixedArrayElement0Offset = 0x8; +const kMapOffset = 0; +const kFuncRefMapTypeInfoOffset = 0x14; +const kTypeInfoSupertypesOffset = 0x10; +let memory = new DataView(new Sandbox.MemoryView(0, 0x100000000)); +function getPtr(obj) { + return Sandbox.getAddressOf(obj) + kHeapObjectTag; +} +function getObj(ofs) { + return Sandbox.getObjectAt(ofs); +} +function getField(obj, offset) { + return memory.getUint32(obj + offset - kHeapObjectTag, true); +} +function setField(obj, offset, value) { + memory.setUint32(obj + offset - kHeapObjectTag, value, true); +} + +let builder = new WasmModuleBuilder(); + +let $u8arr = builder.addArray(kWasmI8, true); +let $sig_i_l = builder.addType(kSig_i_l, kNoSuperType, false); +let $sig_l_l = builder.addType(kSig_l_l, kNoSuperType, false); +let $sig_u8arr_i = builder.addType(makeSig([kWasmI32], [wasmRefType($u8arr)])); +let $sig_i_u8arrl = builder.addType(makeSig([wasmRefType($u8arr), kWasmI64], [kWasmI32])); +let $sig_v_u8arrli = builder.addType(makeSig([wasmRefType($u8arr), kWasmI64, kWasmI32], [])); + +builder.addFunction('fn_i_l', $sig_i_l).addBody([ + ...wasmI32Const(0), +]).exportFunc(); +let $fn_l_l = builder.addFunction('fn_l_l', $sig_l_l).addBody([ + kExprLocalGet, 0, +]).exportFunc(); +let $t = builder.addTable(kWasmAnyFunc, 1, 1, [kExprRefFunc, ...wasmSignedLeb($fn_l_l.index)]); + +builder.addFunction('alloc_u8arr', $sig_u8arr_i).addBody([ + kExprLocalGet, 0, + kGCPrefix, kExprArrayNewDefault, $u8arr, +]).exportFunc(); + +builder.addFunction(`u8arr_get`, $sig_i_u8arrl).addBody([ + kExprLocalGet, 0, + kExprLocalGet, 1, // i64 index + ...wasmI32Const(0), // confuse i64 into i32 with a signature hash compatible function (i64->i64 vs i64->i32) + kExprCallIndirect, ...wasmSignedLeb($sig_i_l), ...wasmSignedLeb($t.index), + kGCPrefix, kExprArrayGetU, ...wasmSignedLeb($u8arr), // array indexing, uses full 64bit regs as is on x86-64 (+ kWasmI8 avoids i32 shl) +]).exportFunc(); + +builder.addFunction(`u8arr_set`, $sig_v_u8arrli).addBody([ + kExprLocalGet, 0, + + kExprLocalGet, 1, + ...wasmI32Const(0), + kExprCallIndirect, ...wasmSignedLeb($sig_i_l), ...wasmSignedLeb($t.index), + kExprLocalGet, 2, + kGCPrefix, kExprArraySet, ...wasmSignedLeb($u8arr), +]).exportFunc(); + +let instance = builder.instantiate(); +let {fn_i_l, fn_l_l, alloc_u8arr, u8arr_get, u8arr_set} = instance.exports; + +function extract_wasmglobal_value(global) { + let pbuf = getField(getPtr(global), kWasmGlobalObjectTaggedBufferOffset); + let pval = getField(pbuf, kFixedArrayElement0Offset); + return pval; +} + +function set_supertype(sub_fn, super_fn) { + let g = new WebAssembly.Global({value: 'anyfunc', mutable: true}); + + g.value = sub_fn; + let funcref_sub = extract_wasmglobal_value(g); // WASM_FUNC_REF_TYPE + let map_sub = getField(funcref_sub, kMapOffset); // Map of WASM_FUNC_REF_TYPE + let typeinfo_sub = getField(map_sub, kFuncRefMapTypeInfoOffset); // WASM_TYPE_INFO_TYPE + + g.value = super_fn; + let funcref_sup = extract_wasmglobal_value(g); + let map_sup = getField(funcref_sup, kMapOffset); + + // typeinfo_sub.supertypes[0] = map_sup + setField(typeinfo_sub, kTypeInfoSupertypesOffset, map_sup); +} + +// set $sig_l_l <: $sig_i_l +set_supertype(fn_l_l, fn_i_l); + +// alloc u8arr of length 0x100000. +let u8arr = alloc_u8arr(0x100000); + +// oob write +let MASK64 = (1n<<64n)-1n; +function write8(ptr, val) { + u8arr_set(u8arr, ptr & MASK64, val); +} +// Try to write at a huge offset; this should get truncated to 32-bit and +// succeed. +write8(0x424200012345n, 0x43);