From 440b0492f2107f962b55211396381ec9c7a82c28 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 16 Aug 2026 17:04:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=B5=8C=E5=A5=97=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E4=BD=93/=E6=96=B9=E6=B3=95=E4=BD=93=20use=20strict=20?= =?UTF-8?q?=E6=8C=87=E4=BB=A4=E7=BA=B3=E5=85=A5=E7=BC=96=E8=AF=91=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E9=94=AE=E9=98=B2=E5=AD=97=E8=8A=82=E7=A0=81=E9=94=99?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_compiler/src/hash/class.rs | 4 +-- crates/oxide_compiler/src/hash/expression.rs | 8 ++--- crates/oxide_compiler/src/hash/mod.rs | 15 ++++++++ crates/oxide_compiler/src/hash/statement.rs | 4 +-- .../tests/hash_collision_tests.rs | 36 +++++++++++++++++++ 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/crates/oxide_compiler/src/hash/class.rs b/crates/oxide_compiler/src/hash/class.rs index 53659fff..6c2c30ad 100644 --- a/crates/oxide_compiler/src/hash/class.rs +++ b/crates/oxide_compiler/src/hash/class.rs @@ -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) => { diff --git a/crates/oxide_compiler/src/hash/expression.rs b/crates/oxide_compiler/src/hash/expression.rs index 49706013..65d44949 100644 --- a/crates/oxide_compiler/src/hash/expression.rs +++ b/crates/oxide_compiler/src/hash/expression.rs @@ -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) => { diff --git a/crates/oxide_compiler/src/hash/mod.rs b/crates/oxide_compiler/src/hash/mod.rs index ca36e5e9..e85b22cb 100644 --- a/crates/oxide_compiler/src/hash/mod.rs +++ b/crates/oxide_compiler/src/hash/mod.rs @@ -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); + } +} diff --git a/crates/oxide_compiler/src/hash/statement.rs b/crates/oxide_compiler/src/hash/statement.rs index 0fc3c69a..9c9976e0 100644 --- a/crates/oxide_compiler/src/hash/statement.rs +++ b/crates/oxide_compiler/src/hash/statement.rs @@ -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); } } diff --git a/crates/oxide_compiler/tests/hash_collision_tests.rs b/crates/oxide_compiler/tests/hash_collision_tests.rs index 84f2d2c7..3167e858 100644 --- a/crates/oxide_compiler/tests/hash_collision_tests.rs +++ b/crates/oxide_compiler/tests/hash_collision_tests.rs @@ -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" + ); +}