[5] DFG ValueRepReduction type confusion via MultiGetByOffset
Severity: High | Component: JSC DFG JIT — ValueRepReductionPhase | 460528e
JIT 컴파일된 코드 내에서 비수치(non-numeric) JSValue의 bit pattern이 unboxed double로 재해석되는 type confusion이 observable effect로 드러나기 때문에 High로 평가되었습니다. 조작된 polymorphic property access를 통해 해당 경로에 도달할 수 있으며, MultiGetByOffset constant case에 대한 per-case validation이 누락되어 있음이 diff에서 직접 확인됩니다 (confidence 0.92).
double에 대한 ValueRepReduction은 MultiGetByOffset case의 constant를 즉시 double로 변환해야 합니다. 이 patch는 순수하게 double로 변환할 수 없는 MultiGetByOffset constant를 후보에서 제외합니다.
Source/JavaScriptCore/dfg/DFGValueRepReductionPhase.cpp
case MultiGetByOffset:
case GetByOffset: {
- if (node->child1().useKind() == RealNumberUse || node->child1().useKind() == NumberUse) {
- if (node->child1()->origin.exitOK)
- candidates.add(node->child1().node());
+ if (node->child1().useKind() != RealNumberUse && node->child1().useKind() != NumberUse)
break;
- }
+ if (!node->child1()->origin.exitOK)
+ break;
+ if (node->child1()->op() == MultiGetByOffset) {
+ bool isCandidate = true;
+ MultiGetByOffsetData& data = node->child1()->multiGetByOffsetData();
+ for (unsigned i = 0; i < data.cases.size(); ++i) {
+ GetByOffsetMethod& method = data.cases[i].method();
+ if (method.kind() == GetByOffsetMethod::Constant && !method.constant()->value().toNumberFromPrimitive()) {
+ isCandidate = false;
+ break;
+ }
+ }
+ if (!isCandidate)
+ break;
+ }
+ candidates.add(node->child1().node());
break;
}
Patch Details
MultiGetByOffset node를 double 변환 후보로 등록하기 전에 validation loop가 추가되었습니다. 새로 추가된 코드는 MultiGetByOffsetData의 모든 case를 순회하면서, Constant 종류의 case 값이 toNumberFromPrimitive()를 통해 순수하게 double로 변환될 수 있는지 확인합니다. 하나라도 변환에 실패하면 해당 node는 후보에서 제외됩니다. 수정 이전에는 MultiGetByOffset이 GetByOffset과 동일하게 취급되어, per-case constant validation 없이 후보로 등록되었습니다.
Polymorphic property load를 unboxed double representation으로 확정하기 전, per-case constant 변환 가능성 검증이 누락된 패턴.
Background
DFG ValueRepReductionPhase는 SSA 형태의 DFG IR 위에서 동작하며, output을 boxed JSValue에서 unboxed machine representation(double, int52, int32)으로 변환할 수 있는 node를 식별합니다. 이를 통해 hot path에서 boxing/unboxing overhead를 줄일 수 있습니다.
MultiGetByOffset은 polymorphic inline cache를 나타내는 DFG node로, 여러 object 구조에 적중하도록 profiling된 property access를 표현합니다. 각 case는 property를 로드하는 방식을 지정하는데, 고정 offset의 object slot에서 읽어오거나 inline constant(GetByOffsetMethod::Constant)로 반환하는 두 가지 형태가 있습니다. toNumberFromPrimitive()는 JSValue를 순수하게 numeric 값으로 변환하는 시도를 수행합니다. 숫자나 numeric string에는 유효한 double을 반환하지만, Symbol, BigInt, 변환이 불가능한 object에 대해서는 실패합니다.
JS property access DFG IR ValueRepReduction
───────────────── ────────────────── ──────────────────────────
obj.x MultiGetByOffset Is every case safely
(profiled: 3 ├─ case S1: offset 16 convertible to double?
structures) ├─ case S2: Constant(42) 42 → 42.0 ✓
└─ case S3: Constant(sym) Symbol → ✗ REJECT
Analysis
수정 이전에는 node를 boxed JSValue에서 unboxed double로 변환할 수 있는지 결정할 때, convertValueRepsToUnboxed<DoubleRepUse>()가 MultiGetByOffset을 GetByOffset과 동일하게 취급했습니다. MultiGetByOffset은 여러 structure case에 걸쳐 dispatch하며, 그 중 일부는 inline constant를 반환할 수 있습니다. 해당 phase가 이러한 node를 double 후보로 표시하면, JIT는 이후 node의 output을 unboxed double로 즉시 변환합니다. constant case 중 하나가 순수하게 double로 변환할 수 없는 값(Symbol, BigInt 등)을 담고 있다면, 이 즉각적인 변환은 잘못된 bit-pattern 재해석을 유발합니다. 즉, raw JSValue encoding이 double로 처리되는 상황이 발생합니다.
이 버그의 근본 원인은 의미론적으로 근본적인 차이가 있음에도 불구하고 MultiGetByOffset과 GetByOffset이 공유 case 구문으로 묶여 있었다는 점에 있습니다. MultiGetByOffset은 GetByOffset에는 없는 inline constant case를 포함합니다.
Aaaa Aaa Aaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aa Aaaaa Aaa Aaaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaa Aaaaaaa Aaa a Aaaaa Aaaaaaaaaaaaaaaaaa Aaa Aaa Aaa Aaa Aaa Aaaaa Aaaa Aaa Aaa Aa Aaaaaaaaa Aaa Aaa Aaaaaaaa Aaaaaaa Aaaaaaa Aaaaaa Aaa Aaaa Aaaaaaaaaa Aaa Aaaaaaa Aa Aaa Aaaa Aaaaaaa Aa Aaaaa Aa Aaaaaaaa Aaaa a Aaa a Aaaaa Aaaaa Aaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaa Aaaaaaa Aaaa Aaaa Aaaaaa Aaa Aa Aaaaaa Aaaa Aa Aaa Aa Aaaaaaaaaa Aaaaaaa Aaaaaaaaaa Aaa Aaaa Aaaaa
a Aaaaaaaaaaaaaa Aaaaaaaa Aaaaaaa a Aaa Aaa Aaa Aaaa Aaaaaaa Aaaaaaa Aaa Aaaaa Aaaa Aaaaaaa Aaaaaa Aaa Aaa Aaaaa Aaaaaaa Aaaaaaa Aaaa Aaaa a Aaa Aaaaaa Aa Aaaa Aaa Aaaaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaa a Aaa Aaa a Aaaaa Aaa Aaa Aaa Aaa Aaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaa Aaa Aaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaaaaa Aa Aaa Aaa a Aa Aaaaaa a Aaaa Aaaaaaaaaa Aaa Aaaaaaaaaa Aaaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaa Aaaa Aaaaa
Aaa Aaaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaaa Aaa Aa Aaaaa Aaaa Aaaa a Aaa Aaaaa Aaaa Aaa Aaa Aaaaaa
Aaaaaaaaa Aa Aa Aa a Aa Aaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaa Aaa Aaaa Aaaaaaaaaaa Aaaa Aaaaa Aaa Aaaaaa Aaaaaa Aa a a Aaa Aaaaaa Aaa Aaaaa Aaaa Aaaaaaaaaa Aaa Aaaaaa Aa Aaaaaa
🔒Explores how polymorphic property access interacts with value representation narrowing and what type confusion primitive this could yield
더 확인하려면 구독해 주세요
Audit directions
a Aaaaaaa Aaaaaaaaaaaaaaa Aaaa Aaa Aaa Aaaaaa Aaaaaaaaaaa Aaaaa Aa Aaa Aaaaaaa Aaaa Aaa Aaaaaaaaaa Aa Aaaaa Aaaa Aaaa Aaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaa Aa Aaa a Aaa Aaaaaa Aaaa Aaaa Aa Aaaaaaaaaaaaaaa Aaaa Aaaaa a Aaaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaa Aaa Aaa Aaaaa Aaaaa Aaa Aaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaa Aaaa Aaa Aaaa Aa Aaaaa
a Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaaaaaaaaaa Aaaaa Aaa Aaaa Aaaa Aaaa Aaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaa Aaa Aaaaa Aaaaaaaaaaa Aaaaa Aaa Aaaa Aaaaaaaaaa Aaaaaaa Aaaa Aa a Aaaaa Aaa Aaaaa Aaa a Aaaaaaa Aaa Aaaa Aaaaaa Aaaa Aa Aaaaaaaa Aaa Aaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaaaa Aaa Aaa Aaa Aaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaa Aa Aaa Aaaaa Aaaaaaaaaaaaaaaaaaa Aaaa Aaa Aaa Aaaa
a Aaaaaaaaaaaaaaa a Aaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aa Aaa Aaaaaaaaaaaaaaaa Aaaa Aaaa Aa Aaa Aaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaaaa Aaaa Aaaa Aaa Aaaa Aaaa Aa Aaa Aaaaa Aaa Aa Aaaaaaaaa Aa Aaaaaaaaaaaaaaa Aaaaa Aaaaa Aa Aaaaa Aa Aa Aaaa Aaaaa Aaa Aaaaaa
🔒Multiple audit patterns identified across DFG optimization phases, with concrete search targets for variant discovery
더 확인하려면 구독해 주세요