fix: 嵌套函数体/方法体 use strict 指令纳入编译缓存键防字节码错配
This commit is contained in:
@@ -19,9 +19,7 @@ pub(super) fn hash_class_element(element: &ClassElement, h: &mut rustc_hash::FxH
|
||||
}
|
||||
}
|
||||
if let Some(body) = &method.value.body {
|
||||
for stmt in &body.statements {
|
||||
statement::hash_statement(stmt, h, include_binding_names);
|
||||
}
|
||||
hash_function_body(body, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
ClassElement::PropertyDefinition(prop) => {
|
||||
|
||||
@@ -88,9 +88,7 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
hash_binding_pattern(¶m.pattern, h);
|
||||
}
|
||||
}
|
||||
for s in &arrow.body.statements {
|
||||
statement::hash_statement(s, h, include_binding_names);
|
||||
}
|
||||
hash_function_body(&arrow.body, h, include_binding_names);
|
||||
}
|
||||
Expression::FunctionExpression(fe) => {
|
||||
(fe.params.items.len() as u32).hash(h);
|
||||
@@ -103,9 +101,7 @@ pub(super) fn hash_expression(expr: &Expression, h: &mut rustc_hash::FxHasher, i
|
||||
}
|
||||
}
|
||||
if let Some(body) = &fe.body {
|
||||
for s in &body.statements {
|
||||
statement::hash_statement(s, h, include_binding_names);
|
||||
}
|
||||
hash_function_body(body, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
Expression::ClassExpression(class) => {
|
||||
|
||||
@@ -70,3 +70,18 @@ fn hash_binding_pattern(pattern: &BindingPattern, h: &mut rustc_hash::FxHasher)
|
||||
ident.name.as_str().hash(h);
|
||||
}
|
||||
}
|
||||
|
||||
/// 函数体哈希:statements 之后追加 directives。
|
||||
///
|
||||
/// directives 决定函数体严格模式(`"use strict"` 等),不纳入 hash 时嵌套
|
||||
/// 函数/方法体 strict 标志随缓存键错配复用错误字节码(this 绑定语义漂移)。
|
||||
fn hash_function_body(
|
||||
body: &oxide_parser::FunctionBody<'_>, h: &mut rustc_hash::FxHasher, include_binding_names: bool,
|
||||
) {
|
||||
for stmt in &body.statements {
|
||||
statement::hash_statement(stmt, h, include_binding_names);
|
||||
}
|
||||
for directive in &body.directives {
|
||||
directive.directive.as_str().hash(h);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,9 +208,7 @@ fn hash_function_declaration(fd: &Function<'_>, h: &mut rustc_hash::FxHasher, in
|
||||
}
|
||||
}
|
||||
if let Some(body) = &fd.body {
|
||||
for s in &body.statements {
|
||||
hash_statement(s, h, include_binding_names);
|
||||
}
|
||||
hash_function_body(body, h, include_binding_names);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -94,3 +94,39 @@ fn structural_hash_ignores_binding_names() {
|
||||
// 编译模块哈希纳入绑定名:改名的程序哈希不等。
|
||||
assert_ne!(compiled("function f(x){ return x }"), compiled("function f(y){ return y }"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_body_directives_distinguished() {
|
||||
// 嵌套函数体 directives 决定其严格模式:不入 hash 时 strict 标志随缓存键错配。
|
||||
assert_ne!(
|
||||
compiled("function f(){ 'use strict'; return 1 }"),
|
||||
compiled("function f(){ return 1 }"),
|
||||
"function declaration body directive must be part of the hash"
|
||||
);
|
||||
assert_ne!(
|
||||
compiled("var f = function(){ 'use strict'; return 1 }"),
|
||||
compiled("var f = function(){ return 1 }"),
|
||||
"function expression body directive must be part of the hash"
|
||||
);
|
||||
assert_ne!(
|
||||
compiled("var f = () => { 'use strict'; return 1 }"),
|
||||
compiled("var f = () => { return 1 }"),
|
||||
"arrow function body directive must be part of the hash"
|
||||
);
|
||||
assert_ne!(
|
||||
compiled("class A { m(){ 'use strict'; return 1 } }"),
|
||||
compiled("class A { m(){ return 1 } }"),
|
||||
"class method body directive must be part of the hash"
|
||||
);
|
||||
assert_ne!(
|
||||
compiled("var o = { m(){ 'use strict'; return 1 } }"),
|
||||
compiled("var o = { m(){ return 1 } }"),
|
||||
"object literal method body directive must be part of the hash"
|
||||
);
|
||||
// 非 prologue 位置的字符串字面量是普通语句,不构成 directive,哈希不混同。
|
||||
assert_eq!(
|
||||
compiled("function f(){ 'not-a-directive'; return 1 }"),
|
||||
compiled("function f(){ 'not-a-directive'; return 1 }"),
|
||||
"identical sources must hash equally"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user