CVE-2026-113044
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Ftest/unittests/parser/ast-value-unittest.cc |
modified | |
iftest/unittests/parser/ast-value-unittest.cc |
modified |
Files Changed
test/unittests/parser/ast-value-unittest.ccsrc/ast/ast-value-factory.ccsrc/objects/string-table.cctest/mjsunit/regress/regress-559266116.jssrc/strings/string-hasher-inl.hsrc/ast/ast-value-factory.h
Patch
From c0543d0cbd1647e9f3a97067128c3144e77a2e17 Mon Sep 17 00:00:00 2001 From: Leszek Swirski <[email protected]> Date: Thu, 17 Sep 2026 15:52:10 +0200 Subject: [PATCH] [ast] Normalize one-byte content in AstValueFactory and StringTable When internalizing a two-byte string that is a valid array index in StringTable::LookupString, StringHasher::HashSequentialString did not set *out_one_byte_content = true in the TryParseArrayIndex fast path. Additionally, if the string already had a computed hash field, LookupString skipped EnsureRawHash and left one_byte_content as false. Consequently, two-byte array-index strings were internalized as TwoByteInternalizedString instead of being canonicalized to one-byte. When AstValueFactory::GetString imported such a string into an AstRawString during lazy compilation, it created a two-byte AstRawString. AstRawString::AsArrayIndex then attempted to parse the uncached array index (> 7 digits) using OneByteStringStream on raw uint16_t storage, failing due to interleaved null bytes and causing a property count mismatch between BuildObjectLiteral and the boilerplate descriptor. Fix this by: 1. Setting *out_one_byte_content = true for array index hashes in StringHasher::HashSequentialString, and setting one_byte_content = true for pre-hashed integer-index strings in StringTable::LookupString. 2. Normalizing two-byte strings with one-byte content to one-byte in AstValueFactory::GetString, and asserting DCHECK(is_one_byte()) in AstRawString::AsArrayIndex. TAG=agy CONV=a59b225f-d8c5-43f1-aeda-b348994ceadf Fixed: 559266116 Change-Id: Ief04967add1560b08fa250560fd83cf49039090e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8423180 Reviewed-by: Toon Verwaest <[email protected]> Auto-Submit: Leszek Swirski <[email protected]> Commit-Queue: Toon Verwaest <[email protected]> Cr-Commit-Position: refs/heads/main@{#109931} --- diff --git a/src/ast/ast-value-factory.cc b/src/ast/ast-value-factory.cc index ed113ac..0e2f626 100644 --- a/src/ast/ast-value-factory.cc +++ b/src/ast/ast-value-factory.cc @@ -29,6 +29,7 @@ #include "src/base/hashmap-entry.h" #include "src/base/logging.h" +#include "src/base/small-vector.h" #include "src/common/globals.h" #include "src/heap/factory-inl.h" #include "src/heap/local-factory-inl.h" @@ -82,6 +83,7 @@ // The StringHasher will set up the hash. Bail out early if we know it // can't be convertible to an array index. if (!IsIntegerIndex()) return false; + DCHECK(is_one_byte()); if (length() <= Name::kMaxCachedArrayIndexLength) { *index = StringHasher::DecodeArrayIndexFromHashField( raw_hash_field_, HashSeed(GetReadOnlyRoots())); @@ -340,6 +342,7 @@ const AstRawString* AstValueFactory::GetTwoByteStringInternal( base::Vector<const uint16_t> literal) { + DCHECK(!String::IsOneByte(literal.begin(), literal.length())); uint32_t raw_hash_field = StringHasher::HashSequentialString<uint16_t>( literal.begin(), literal.length(), hash_seed_); return GetString(raw_hash_field, false, @@ -349,16 +352,20 @@ const AstRawString* AstValueFactory::GetString( Tagged<String> literal, const SharedStringAccessGuardIfNeeded& access_guard) { - const AstRawString* result = nullptr; DisallowGarbageCollection no_gc; String::FlatContent content = literal->GetFlatContent(no_gc, access_guard); if (content.IsOneByte()) { - result = GetOneByteStringInternal(content.ToOneByteVector()); - } else { - DCHECK(content.IsTwoByte()); - result = GetTwoByteStringInternal(content.ToUC16Vector()); + return GetOneByteStringInternal(content.ToOneByteVector()); } - return result; + DCHECK(content.IsTwoByte()); + base::Vector<const uint16_t> vector = content.ToUC16Vector(); + if (String::IsOneByte(vector.begin(), vector.length())) { + base::SmallVector<uint8_t, 64> one_byte(vector.length()); + CopyChars(one_byte.data(), vector.begin(), vector.length()); + return GetOneByteStringInternal( + base::Vector<const uint8_t>(one_byte.data(), vector.length())); + } + return GetTwoByteStringInternal(vector); } AstConsString* AstValueFactory::NewConsString() { diff --git a/src/ast/ast-value-factory.h b/src/ast/ast-value-factory.h index 5ca83bc..23b37a9 100644 --- a/src/ast/ast-value-factory.h +++ b/src/ast/ast-value-factory.h @@ -63,7 +63,7 @@ return is_one_byte() ? literal_bytes_.length() : literal_bytes_.length() / 2; } - bool AsArrayIndex(uint32_t* index) const; + V8_EXPORT_PRIVATE bool AsArrayIndex(uint32_t* index) const; bool IsIntegerIndex() const; V8_EXPORT_PRIVATE bool IsOneByteEqualTo(const char* data) const; V8_EXPORT_PRIVATE uint16_t FirstCharacter() const; @@ -383,8 +383,8 @@ const AstRawString* GetTwoByteString(base::Vector<const uint16_t> literal) { return GetTwoByteStringInternal(literal); } - const AstRawString* GetString(Tagged<String> literal, - const SharedStringAccessGuardIfNeeded&); + V8_EXPORT_PRIVATE const AstRawString* GetString( + Tagged<String> literal, const SharedStringAccessGuardIfNeeded&); V8_EXPORT_PRIVATE AstConsString* NewConsString(); V8_EXPORT_PRIVATE AstConsString* NewConsString(const AstRawString* str); diff --git a/src/objects/string-table.cc b/src/objects/string-table.cc index ebf99c3..b62b7cf 100644 --- a/src/objects/string-table.cc +++ b/src/objects/string-table.cc @@ -417,6 +417,8 @@ bool one_byte_content = false; if (!Name::IsHashFieldComputed(raw_hash_field)) { raw_hash_field = flat_string->EnsureRawHash(&one_byte_content); + } else if (Name::IsIntegerIndex(raw_hash_field)) { + one_byte_content = true; } InternalizedStringKey key(flat_string, raw_hash_field, one_byte_content); result = LookupKey(isolate, &key); diff --git a/src/strings/string-hasher-inl.h b/src/strings/string-hasher-inl.h index 1308c98..14b6312 100644 --- a/src/strings/string-hasher-inl.h +++ b/src/strings/string-hasher-inl.h @@ -313,6 +313,7 @@ switch (detail::TryParseArrayIndex(chars, length, i, index)) { case detail::kSuccess: { DCHECK_LE(index, String::kMaxArrayIndex); + if (out_one_byte_content) *out_one_byte_content = true; return StringHasher::MakeArrayIndexHash(static_cast<uint32_t>(index), length, seed); } diff --git a/test/mjsunit/regress/regress-559266116.js b/test/mjsunit/regress/regress-559266116.js new file mode 100644 index 0000000..14bc7bc --- /dev/null +++ b/test/mjsunit/regress/regress-559266116.js @@ -0,0 +1,20 @@ +// 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 + +const key1 = String.fromCharCode(49, 48, 48, 48, 0x130, 48, 48, 48, 48, 48) + .replace(/(\u0130)()/g, '$2'); +Symbol.for(key1); +const object1 = + (0, eval)(`({${key1}(v){return Object.values({"${key1}":v})[1]}})`); +assertEquals(undefined, object1[key1](1)); + +const key2 = String.fromCharCode(49, 48, 48, 48, 0x130, 48, 48, 48, 48, 49) + .replace(/(\u0130)()/g, '$2'); +new Set().add(key2); +Symbol.for(key2); +const object2 = + (0, eval)(`({${key2}(v){return Object.values({"${key2}":v})[1]}})`); +assertEquals(undefined, object2[key2](1)); diff --git a/test/unittests/parser/ast-value-unittest.cc b/test/unittests/parser/ast-value-unittest.cc index 91efc9e..57441b4 100644 --- a/test/unittests/parser/ast-value-unittest.cc +++ b/test/unittests/parser/ast-value-unittest.cc @@ -26,10 +26,98 @@ kNoSourcePosition); } + const AstRawString* GetOneByteString(const char* str) { + return ast_value_factory_.GetOneByteString(str); + } + + DirectHandle<String> CreateTwoByteString(const char* str) { + int length = static_cast<int>(strlen(str)); + DirectHandle<SeqTwoByteString> result = + i_isolate()->factory()->NewRawTwoByteString(length).ToHandleChecked(); + DisallowGarbageCollection no_gc; + CopyChars(result->GetChars(no_gc), str, length); + return result; + } + + DirectHandle<String> CreateTwoByteStringWithNonOneByte() { + DirectHandle<SeqTwoByteString> result = + i_isolate()->factory()->NewRawTwoByteString(1).ToHandleChecked(); + DisallowGarbageCollection no_gc; + result->GetChars(no_gc)[0] = 0x1234; + return result; + } + AstValueFactory ast_value_factory_; AstNodeFactory ast_node_factory_; }; +TEST_F(AstValueTest, AstRawStringAsArrayIndex) { + auto test_as_array_index = [&](const char* str, bool expected_success, + uint32_t expected_index) { + const AstRawString* one_byte = GetOneByteString(str); + EXPECT_TRUE(one_byte->is_one_byte()); + uint32_t index = 0; + EXPECT_EQ(one_byte->AsArrayIndex(&index), expected_success); + if (expected_success) { + EXPECT_EQ(index, expected_index); + } + }; + + // Cached array index (length <= Name::kMaxCachedArrayIndexLength). + test_as_array_index("0", true, 0); + test_as_array_index("1", true, 1); + test_as_array_index("1234567", true, 1234567); + + // Uncached array index (length > 7 and <= Name::kMaxArrayIndexSize). + test_as_array_index("12345678", true, 12345678); + test_as_array_index("1000000000", true, 1000000000); + + // Max valid array index (4294967294). + test_as_array_index("4294967294", true, 4294967294u); + + // Overflow (length 10, > 4294967294). + test_as_array_index("4294967295", false, 0); + test_as_array_index("5000000000", false, 0); + + // Overflow (length > 10, > Name::kMaxArrayIndexSize). + test_as_array_index("10000000000", false, 0); + + // Non-index strings. + test_as_array_index("01", false, 0); + test_as_array_index("foo", false, 0); +} + +TEST_F(AstValueTest, GetStringNormalizesOneByteContent) { + DirectHandle<String> two_byte_str = CreateTwoByteString("1000000000"); + EXPECT_TRUE(two_byte_str->IsTwoByteRepresentation()); + const AstRawString* raw = ast_value_factory_.GetString( + *two_byte_str, SharedStringAccessGuardIfNeeded::NotNeeded()); + EXPECT_TRUE(raw->is_one_byte()); + uint32_t index = 0; + EXPECT_TRUE(raw->AsArrayIndex(&index)); + EXPECT_EQ(index, 1000000000u); + + // Also check that internalizing a two-byte integer-index string (unhashed or + // pre-hashed) canonicalizes it to one-byte in the StringTable. + DirectHandle<String> internalized_unhashed = + i_isolate()->factory()->InternalizeString(two_byte_str); + EXPECT_TRUE(internalized_unhashed->IsOneByteRepresentation()); + + DirectHandle<String> prehashed_two_byte_str = + CreateTwoByteString("1000000001"); + prehashed_two_byte_str->EnsureRawHash(); + DirectHandle<String> internalized_prehashed = + i_isolate()->factory()->InternalizeString(prehashed_two_byte_str); + EXPECT_TRUE(internalized_prehashed->IsOneByteRepresentation()); + + DirectHandle<String> non_one_byte_str = CreateTwoByteStringWithNonOneByte(); + EXPECT_TRUE(non_one_byte_str->IsTwoByteRepresentation()); + const AstRawString* raw_non_one_byte = ast_value_factory_.GetString( + *non_one_byte_str, SharedStringAccessGuardIfNeeded::NotNeeded()); + EXPECT_FALSE(raw_non_one_byte->is_one_byte()); + EXPECT_FALSE(raw_non_one_byte->AsArrayIndex(&index)); +} + TEST_F(AstValueTest, BigIntToBooleanIsTrue) { EXPECT_FALSE(NewBigInt("0")->ToBooleanIsTrue()); EXPECT_FALSE(NewBigInt("0b0")->ToBooleanIsTrue());
Regression Test / PoC
diff --git a/test/mjsunit/regress/regress-559266116.js b/test/mjsunit/regress/regress-559266116.js
new file mode 100644
index 0000000..14bc7bc
--- /dev/null
+++ b/test/mjsunit/regress/regress-559266116.js
@@ -0,0 +1,20 @@
+// 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
+
+const key1 = String.fromCharCode(49, 48, 48, 48, 0x130, 48, 48, 48, 48, 48)
+ .replace(/(\u0130)()/g, '$2');
+Symbol.for(key1);
+const object1 =
+ (0, eval)(`({${key1}(v){return Object.values({"${key1}":v})[1]}})`);
+assertEquals(undefined, object1[key1](1));
+
+const key2 = String.fromCharCode(49, 48, 48, 48, 0x130, 48, 48, 48, 48, 49)
+ .replace(/(\u0130)()/g, '$2');
+new Set().add(key2);
+Symbol.for(key2);
+const object2 =
+ (0, eval)(`({${key2}(v){return Object.values({"${key2}":v})[1]}})`);
+assertEquals(undefined, object2[key2](1));
diff --git a/test/unittests/parser/ast-value-unittest.cc b/test/unittests/parser/ast-value-unittest.cc
index 91efc9e..57441b4 100644
--- a/test/unittests/parser/ast-value-unittest.cc
+++ b/test/unittests/parser/ast-value-unittest.cc
@@ -26,10 +26,98 @@
kNoSourcePosition);
}
+ const AstRawString* GetOneByteString(const char* str) {
+ return ast_value_factory_.GetOneByteString(str);
+ }
+
+ DirectHandle<String> CreateTwoByteString(const char* str) {
+ int length = static_cast<int>(strlen(str));
+ DirectHandle<SeqTwoByteString> result =
+ i_isolate()->factory()->NewRawTwoByteString(length).ToHandleChecked();
+ DisallowGarbageCollection no_gc;
+ CopyChars(result->GetChars(no_gc), str, length);
+ return result;
+ }
+
+ DirectHandle<String> CreateTwoByteStringWithNonOneByte() {
+ DirectHandle<SeqTwoByteString> result =
+ i_isolate()->factory()->NewRawTwoByteString(1).ToHandleChecked();
+ DisallowGarbageCollection no_gc;
+ result->GetChars(no_gc)[0] = 0x1234;
+ return result;
+ }
+
AstValueFactory ast_value_factory_;
AstNodeFactory ast_node_factory_;
};
+TEST_F(AstValueTest, AstRawStringAsArrayIndex) {
+ auto test_as_array_index = [&](const char* str, bool expected_success,
+ uint32_t expected_index) {
+ const AstRawString* one_byte = GetOneByteString(str);
+ EXPECT_TRUE(one_byte->is_one_byte());
+ uint32_t index = 0;
+ EXPECT_EQ(one_byte->AsArrayIndex(&index), expected_success);
+ if (expected_success) {
+ EXPECT_EQ(index, expected_index);
+ }
+ };
+
+ // Cached array index (length <= Name::kMaxCachedArrayIndexLength).
+ test_as_array_index("0", true, 0);
+ test_as_array_index("1", true, 1);
+ test_as_array_index("1234567", true, 1234567);
+
+ // Uncached array index (length > 7 and <= Name::kMaxArrayIndexSize).
+ test_as_array_index("12345678", true, 12345678);
+ test_as_array_index("1000000000", true, 1000000000);
+
+ // Max valid array index (4294967294).
+ test_as_array_index("4294967294", true, 4294967294u);
+
+ // Overflow (length 10, > 4294967294).
+ test_as_array_index("4294967295", false, 0);
+ test_as_array_index("5000000000", false, 0);
+
+ // Overflow (length > 10, > Name::kMaxArrayIndexSize).
+ test_as_array_index("10000000000", false, 0);
+
+ // Non-index strings.
+ test_as_array_index("01", false, 0);
+ test_as_array_index("foo", false, 0);
+}
+
+TEST_F(AstValueTest, GetStringNormalizesOneByteContent) {
+ DirectHandle<String> two_byte_str = CreateTwoByteString("1000000000");
+ EXPECT_TRUE(two_byte_str->IsTwoByteRepresentation());
+ const AstRawString* raw = ast_value_factory_.GetString(
+ *two_byte_str, SharedStringAccessGuardIfNeeded::NotNeeded());
+ EXPECT_TRUE(raw->is_one_byte());
+ uint32_t index = 0;
+ EXPECT_TRUE(raw->AsArrayIndex(&index));
+ EXPECT_EQ(index, 1000000000u);
+
+ // Also check that internalizing a two-byte integer-index string (unhashed or
+ // pre-hashed) canonicalizes it to one-byte in the StringTable.
+ DirectHandle<String> internalized_unhashed =
+ i_isolate()->factory()->InternalizeString(two_byte_str);
+ EXPECT_TRUE(internalized_unhashed->IsOneByteRepresentation());
+
+ DirectHandle<String> prehashed_two_byte_str =
+ CreateTwoByteString("1000000001");
+ prehashed_two_byte_str->EnsureRawHash();
+ DirectHandle<String> internalized_prehashed =
+ i_isolate()->factory()->InternalizeString(prehashed_two_byte_str);
+ EXPECT_TRUE(internalized_prehashed->IsOneByteRepresentation());
+
+ DirectHandle<String> non_one_byte_str = CreateTwoByteStringWithNonOneByte();
+ EXPECT_TRUE(non_one_byte_str->IsTwoByteRepresentation());
+ const AstRawString* raw_non_one_byte = ast_value_factory_.GetString(
+ *non_one_byte_str, SharedStringAccessGuardIfNeeded::NotNeeded());
+ EXPECT_FALSE(raw_non_one_byte->is_one_byte());
+ EXPECT_FALSE(raw_non_one_byte->AsArrayIndex(&index));
+}
+
TEST_F(AstValueTest, BigIntToBooleanIsTrue) {
EXPECT_FALSE(NewBigInt("0")->ToBooleanIsTrue());
EXPECT_FALSE(NewBigInt("0b0")->ToBooleanIsTrue());
Original Bug Report
# V8 two-byte array-index parsing leaks the uninitialized hole and enables caged read/write
V8 contains a type-confusion vulnerability in the JavaScript parser’s handling of numeric property names. During lazy reparsing, the parser can read a two-byte string as one-byte data and classify a valid array index as a named property. Object-literal initialization then leaves that named field uninitialized, and Object.values exposes V8’s internal hole value to JavaScript. Using the hole in optimized code enables arbitrary read/write within the 4 GiB pointer-compression cage.
Tested version: V8 15.5.0 (candidate), main 6eb1420c4f60570474ef66bdda19b68b0a0390eb, standard release d8 on Linux x64.
Root cause
AstRawString::AsArrayIndex correctly recognizes an integer-index hash, but its slow conversion always treats the raw storage as one-byte characters:
OneByteStringStream stream(literal_bytes_);
return StringToIndex(&stream, index);
This matters for valid numeric names longer than the seven-character cached-index limit. A two-byte ASCII string contains interspersed zero bytes on little-endian x64, so this conversion returns false even though the string is a valid array index.
The scanner normally supplies one-byte ASCII names. The reachable exception is lazy function reparsing: Parser::ParseFunction inserts the heap function name into the parser’s string table before scanning its body, and AstValueFactory::GetString preserves that heap string’s encoding:
info->set_function_name(ast_value_factory()->GetString(
shared_info->Name(), SharedStringAccessGuardIfNeeded(isolate)));
scanner_.Initialize();
The PoC creates a two-byte string, removes its sole non-ASCII character, promotes it, and internalizes it with Symbol.for. It then uses the same nine-digit name for a lazy method and an object-literal key. These are the triggering lines from poc/v8-two-byte-array-index-crash.js:
const key = String.fromCharCode(...[1, digit(), digit(), digit(), 0x100,
digit(), digit(), digit(), digit(), digit()].map(x => x + 48))
.replace(/(\u0130)()/g, '$2');
promote();
Symbol.for(key);
const object = (0, eval)(`({${key}(v){return Object.values({"${key}":v})[1]}})`);
const value = object[key](1);
if (value === undefined) continue;
JSON.stringify(value);
During object-literal construction, BuildBoilerplateDescription chooses between an element index and a named property using the incorrect result:
if (key_literal->AsArrayIndex(&element_index)) {
key =
isolate->factory()->template NewNumberFromUint<AllocationType::kOld>(
element_index);
} else {
key = key_literal->AsRawPropertyName()->string();
}
Because v is evaluated at runtime, GetBoilerplateValue initially supplies uninitialized_value(). The runtime initialization writes the real numeric element, leaving the incorrectly created named field untouched. Object.values exposes that leftover internal value as a second entry. The crash-only PoC passes it to JSON.stringify, which reaches the HOLE_TYPE unreachable case.
The leaked hole enables further memory corruption. CanHoldValue accepts it before checking a data field’s representation:
if (IsUninitializedHole(value)) return true;
return Object::FitsRepresentation(value, details.representation()) &&
FieldType::NowContains(descriptors->GetFieldType(descriptor),
value);
v8-two-byte-array-index-caged-rw.js puts the hole into a field optimized as a small integer. Optimized arithmetic and array allocation then produce an off-by-one double-array access that redirects a DataView over the compression cage. The script changes an unrelated ArrayBuffer’s reported length and restores it. The offsets and allocation strategy target the tested x64 build.
Reproduction
Run the PoCs with standard release d8:
d8 --run-as-security-poc poc/v8-two-byte-array-index-crash.js
d8 --run-as-security-poc poc/v8-two-byte-array-index-caged-rw.js
The crash PoC reported Fatal error / unreachable code and exited with SIGABRT (134) in 10/10 security-mode runs. It also crashed without flags (exit 133). An ordinary-method-name negative control returned undefined without crashing.
The caged-read/write PoC passed 20/20 fresh security-mode processes and one no-flags run. Observed output:
Caged read: ArrayBuffer byteLength = 16
Caged write: ArrayBuffer byteLength = 1048576
Restored ArrayBuffer byteLength = 16
PASS: caged arbitrary read/write
The length is restored before exit. The PoC deliberately corrupts its own process heap and should be run in a disposable d8 process.
Affected-version source bounds and proposed fix
The encoding-blind conversion predates the 2020 hash-field change, which replaced a CHECK on conversion failure with a boolean return. The adjacent 8.2.98 snapshot still checks the conversion; 8.2.99 contains the false-returning path. The same path is present in inspected tags 9.0.257.43, 12.0.267.36, and 14.0.365.4. These snapshots establish the conversion’s source history. Runtime validation confirms V8 15.5.0 (candidate). The exact first-affected and fixed releases remain undetermined.
The proposed fix is to parse array indices according to the actual one-byte or two-byte encoding, and ensure the parser and runtime classify literal keys identically. Regression coverage should include a two-byte internalized numeric function name, the lazy reparse and dynamic object-literal value above, an ordinary-name control, and numeric keys on both sides of the cached-index-length boundary.
Disclaimer
This information is being shared by OpenAI solely for the purpose of improving security and reducing potential harm. This information is presented as-is. We make no representations or warranties, express or implied, as to the completeness, accuracy, or fitness for any particular purpose of the information. This includes, without limitation any suggestions or ideas presented on how to remedy or mitigate an identified vulnerability, including whether such suggestions or ideas would be effective and/or could have other negative impacts.
OpenAI disclaims any liability for direct or indirect damages arising from the reliance on, or use, misuse, or interpretation of this information. Any references to third-party systems, services, or entities are included solely for identification purposes and do not imply endorsement, responsibility, or attribution.
CREDIT INFORMATION
OpenAI Codex Security (amyb)
- https://github.com/v8/v8/blob/3928d1150988f0350daf7ce84d1c27aefe737681/src/ast/ast-value-factory.cc
- https://github.com/v8/v8/blob/54cfb999d47070ad58d2b39f2089005828fd79eb/src/ast/ast-value-factory.cc
- https://github.com/v8/v8/blob/5d02023981f2579db9b6d528fb60e53db6f17a6c/src/ast/ast-value-factory.cc
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/ast/ast-value-factory.cc#L349-L361
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/ast/ast-value-factory.cc#L81-L95
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/ast/ast.cc#L597-L612
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/ast/ast.cc#L639-L656
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/json/json-stringifier.cc#L1063-L1064
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/objects/map.cc#L2051-L2060
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/objects/name.h#L197-L202
- https://github.com/v8/v8/blob/6eb1420c4f60570474ef66bdda19b68b0a0390eb/src/parsing/parser.cc#L1087-L1092
- https://github.com/v8/v8/blob/db7b7149bfebae517d6d4ff9bc2d01bda45423d1/src/ast/ast-value-factory.cc
- https://github.com/v8/v8/blob/fdb12b460f148895f6af2ff0e0d870ff8889f154/src/ast/ast-value-factory.cc
- https://github.com/v8/v8/commit/8d7747a715bb4e4d3682e590dfc79c8c8ae05c65
- https://github.com/v8/v8/tree/6eb1420c4f60570474ef66bdda19b68b0a0390eb