[10] [JSC] StringAt should respect arrayMode in CSE
Severity: High | Component: JSC DFG JIT | 1f4e4ca
High 평가. String.prototype.at의 잘못된 CSE 패치. GCSE 키에서 arrayMode 누락. in-bounds (String 반환)와 OOB (undefined 반환) 연산 병합. JIT-IR 수준 type confusion. 웹 JS에서 도달 가능.
StringAt은 StringCharAt의 def(PureValue(node)) 절로 fall through되었습니다. charAt은 반환 타입이 일정합니다. OOB의 경우에도 항상 빈 문자열을 반환합니다. 반면 at은 범위에 따라 반환 타입이 달라집니다. 범위 내이면 string을, 범위 밖이면 undefined를 반환합니다.
Source/JavaScriptCore/dfg/DFGClobberize.h
case StringAt:
+ def(PureValue(node, node->arrayMode().asWord()));
+ return;
case StringCharAt:
def(PureValue(node));
return;
Patch Details
StringAt에 별도의 case가 추가되어 def(PureValue(node, node->arrayMode().asWord()))를 호출합니다. 이로써 ArrayMode가 CSE 키에 포함되고, array mode가 다른 node들은 더 이상 병합되지 않습니다.
CSE 키에서 연산의 반환 타입을 결정하는 mode 구분자가 누락되어, optimizer가 출력 타입 계약이 서로 다른 두 연산을 병합하게 됩니다.
Background
clobberize()는 pure node에 대한 CSE를 구동하기 위해 read/write/def 요약을 생성합니다. PureValue는 side effect가 없는 node의 CSE 키로, 기본적으로 (opcode, child edges)를 해시하는데, PureValue(node, word) 형태로 추가 구분자를 삽입하는 것도 가능합니다. ArrayMode는 DFG에서 indexed 연산을 node별로 특수화하는 정보이며, bytecode별 array profile에서 도출됩니다. String.prototype.at(i)와 charAt의 핵심 차이는 OOB 처리에 있습니다. charAt은 OOB에서 빈 문자열을 반환하지만, at은 undefined를 반환합니다.
Analysis
같은 함수 안에 있는 두 s.at(i) 호출은 서로 다른 방식으로 특수화될 수 있습니다. 하나는 in-bounds 전용 String 모드로, 다른 하나는 OOB를 감지하는 Generic 모드입니다. ArrayMode가 빠진 PureValue(node) 키를 공유하는 상황에서는, string과 index 입력이 동일하다는 이유만으로 CSE가 mode-A StringAt과 mode-B StringAt을 병합하게 됩니다.
Aa a Aaa Aaaaaa Aaaa Aaa Aaaaaaaaa Aaaa Aaaaa Aaa Aaaaaaaaaa Aaaaaa a Aaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaa Aa Aa Aaa Aaaa Aa Aaa Aaaaa Aaaaa Aaaaa Aaaaaaaaa Aaaaaaaaaaa Aaa Aaaa Aaaaaaaaaa Aaaaaa Aa Aaaa Aaaaaaaaaaaaa Aaaa Aaaaaa Aaa Aaaa Aaaa Aaa Aa Aaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaa Aaaaaa Aaaa Aaaaaa Aaa Aa Aaaaaaaaaa Aaa Aa Aaa Aaaaaa Aaa Aaaa Aaaaaaaaaa Aaa Aaaaaa Aaaaaaaaa Aaaaaaaaaaaa Aaa Aa Aaa Aaaa Aaaaaaaaaa Aaaa Aa Aaaaaa
a Aaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaa Aaaa Aaaa Aa Aaa Aa Aaa Aaaaaaa Aaaa Aaa a Aaaaa Aa Aaa Aaaa Aaaa a Aaaa Aaa Aaaaaa
🔒Explores how a missing discriminator in a JIT optimizer's deduplication key turns a benign-looking pure-value handler into a type-confusion primitive, and what downstream escalation would require.
더 확인하려면 구독해 주세요
Audit directions
a Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aa Aa Aaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa a Aaaaaaa Aaaaaaaaa Aa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaa Aaaaa a Aaaaaaa Aaaaaaaaaaaa Aaaa Aaaa Aaaa
a Aaaaaaaaaaaaa Aaaaa Aaaa Aa Aaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaa Aa Aaaaaa Aaaa Aaaaaa Aa Aaaaa Aa Aa Aa Aaa Aaaaa Aaaa Aaaa
a Aaaaaaa Aa Aaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaaaaaaa Aaaaa Aaa Aa Aaaaaaaaa Aa Aaa Aaa Aa Aaa Aaaaa Aaaa Aaaa
a Aaaaaa Aaa Aaaaaa Aa Aaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaa Aa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa a Aaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaa Aaaa Aaaa
🔒Four reusable audit patterns for DFG CSE-key soundness, with specific starting files in the JSC tree for variant discovery.
더 확인하려면 구독해 주세요