@@ -17,7 +17,7 @@ use crate::{
1717 raise_eval_error, raise_reference_error,
1818 unicode:: { utf8_to_utf16, utf16_to_utf8} ,
1919} ;
20- use crate :: { Token , parse_statements, raise_type_error, tokenize} ;
20+ use crate :: { Token , parse_statements, raise_syntax_error , raise_type_error, tokenize} ;
2121use num_bigint:: BigInt ;
2222use num_traits:: { FromPrimitive , ToPrimitive , Zero } ;
2323
@@ -1024,14 +1024,134 @@ pub fn evaluate_statements_with_context<'gc>(
10241024 evaluate_statements_with_labels ( mc, env, statements, labels, & [ ] )
10251025}
10261026
1027+ fn check_expr_for_arguments_assignment ( e : & Expr ) -> bool {
1028+ match e {
1029+ Expr :: Assign ( lhs, _rhs) => {
1030+ if let Expr :: Var ( name, ..) = & * * lhs {
1031+ return name == "arguments" ;
1032+ }
1033+ false
1034+ }
1035+ Expr :: Property ( obj, _)
1036+ | Expr :: Call ( obj, _)
1037+ | Expr :: New ( obj, _)
1038+ | Expr :: Index ( obj, _)
1039+ | Expr :: OptionalProperty ( obj, _)
1040+ | Expr :: OptionalCall ( obj, _)
1041+ | Expr :: OptionalIndex ( obj, _) => check_expr_for_arguments_assignment ( obj) ,
1042+ Expr :: Binary ( l, _, r) | Expr :: Comma ( l, r) | Expr :: Conditional ( l, r, _) => {
1043+ check_expr_for_arguments_assignment ( l) || check_expr_for_arguments_assignment ( r)
1044+ }
1045+ Expr :: LogicalAnd ( l, r) | Expr :: LogicalOr ( l, r) | Expr :: NullishCoalescing ( l, r) => {
1046+ check_expr_for_arguments_assignment ( l) || check_expr_for_arguments_assignment ( r)
1047+ }
1048+ Expr :: AddAssign ( l, r)
1049+ | Expr :: SubAssign ( l, r)
1050+ | Expr :: MulAssign ( l, r)
1051+ | Expr :: DivAssign ( l, r)
1052+ | Expr :: ModAssign ( l, r)
1053+ | Expr :: BitAndAssign ( l, r)
1054+ | Expr :: BitOrAssign ( l, r)
1055+ | Expr :: BitXorAssign ( l, r)
1056+ | Expr :: LeftShiftAssign ( l, r)
1057+ | Expr :: RightShiftAssign ( l, r)
1058+ | Expr :: UnsignedRightShiftAssign ( l, r)
1059+ | Expr :: LogicalAndAssign ( l, r)
1060+ | Expr :: LogicalOrAssign ( l, r)
1061+ | Expr :: NullishAssign ( l, r) => check_expr_for_arguments_assignment ( l) || check_expr_for_arguments_assignment ( r) ,
1062+ Expr :: UnaryNeg ( inner)
1063+ | Expr :: UnaryPlus ( inner)
1064+ | Expr :: LogicalNot ( inner)
1065+ | Expr :: TypeOf ( inner)
1066+ | Expr :: Delete ( inner)
1067+ | Expr :: Void ( inner)
1068+ | Expr :: Await ( inner)
1069+ | Expr :: Yield ( Some ( inner) )
1070+ | Expr :: YieldStar ( inner)
1071+ | Expr :: PostIncrement ( inner)
1072+ | Expr :: PostDecrement ( inner)
1073+ | Expr :: Increment ( inner)
1074+ | Expr :: Decrement ( inner) => check_expr_for_arguments_assignment ( inner) ,
1075+ _ => false ,
1076+ }
1077+ }
1078+
1079+ fn check_stmt_for_arguments_assignment ( stmt : & Statement ) -> bool {
1080+ match & * stmt. kind {
1081+ StatementKind :: Expr ( e) => check_expr_for_arguments_assignment ( e) ,
1082+ StatementKind :: If ( if_stmt) => {
1083+ check_expr_for_arguments_assignment ( & if_stmt. condition )
1084+ || if_stmt. then_body . iter ( ) . any ( check_stmt_for_arguments_assignment)
1085+ || if_stmt
1086+ . else_body
1087+ . as_ref ( )
1088+ . is_some_and ( |b| b. iter ( ) . any ( check_stmt_for_arguments_assignment) )
1089+ }
1090+ StatementKind :: Block ( stmts) => stmts. iter ( ) . any ( check_stmt_for_arguments_assignment) ,
1091+ StatementKind :: TryCatch ( try_stmt) => {
1092+ try_stmt. try_body . iter ( ) . any ( check_stmt_for_arguments_assignment)
1093+ || try_stmt
1094+ . catch_body
1095+ . as_ref ( )
1096+ . is_some_and ( |b| b. iter ( ) . any ( check_stmt_for_arguments_assignment) )
1097+ || try_stmt
1098+ . finally_body
1099+ . as_ref ( )
1100+ . is_some_and ( |b| b. iter ( ) . any ( check_stmt_for_arguments_assignment) )
1101+ }
1102+ StatementKind :: FunctionDeclaration ( _, _, body, _, _) => body. iter ( ) . any ( check_stmt_for_arguments_assignment) ,
1103+ _ => false ,
1104+ }
1105+ }
1106+
10271107pub fn evaluate_statements_with_labels < ' gc > (
10281108 mc : & MutationContext < ' gc > ,
10291109 env : & JSObjectDataPtr < ' gc > ,
10301110 statements : & [ Statement ] ,
10311111 labels : & [ String ] ,
10321112 own_labels : & [ String ] ,
10331113) -> Result < ControlFlow < ' gc > , EvalError < ' gc > > {
1114+ // If this statement sequence begins with a "use strict" directive, mark the
1115+ // environment so eval'd code and nested parsing can behave as strict code.
1116+ if let Some ( stmt0) = statements. first ( )
1117+ && let StatementKind :: Expr ( expr) = & * stmt0. kind
1118+ && let Expr :: StringLit ( s) = expr
1119+ && utf16_to_utf8 ( s) . as_str ( ) == "use strict"
1120+ {
1121+ log:: trace!( "evaluate_statements: detected 'use strict' directive; marking env as strict" ) ;
1122+ object_set_key_value ( mc, env, "__is_strict" , Value :: Boolean ( true ) ) . map_err ( EvalError :: Js ) ?;
1123+ }
1124+
10341125 hoist_declarations ( mc, env, statements) ?;
1126+
1127+ // If the environment is marked strict, scan for certain forbidden patterns
1128+ // such as assignment to the Identifier 'arguments' in function bodies which
1129+ // should be a SyntaxError under strict mode (matching Test262 expectations
1130+ // for eval'd code in strict contexts).
1131+ if let Some ( is_strict_cell) = object_get_key_value ( env, "__is_strict" )
1132+ && let Value :: Boolean ( true ) = * is_strict_cell. borrow ( )
1133+ {
1134+ for stmt in statements {
1135+ if check_stmt_for_arguments_assignment ( stmt) {
1136+ log:: debug!( "evaluate_statements: detected assignment to 'arguments' in function body under strict mode" ) ;
1137+ // Construct a SyntaxError object and throw it so it behaves like a JS exception
1138+ if let Some ( syn_ctor_val) = object_get_key_value ( env, "SyntaxError" )
1139+ && let Value :: Object ( syn_ctor) = & * syn_ctor_val. borrow ( )
1140+ && let Some ( proto_val_rc) = object_get_key_value ( syn_ctor, "prototype" )
1141+ && let Value :: Object ( proto_ptr) = & * proto_val_rc. borrow ( )
1142+ {
1143+ let msg = Value :: String ( utf8_to_utf16 ( "Strict mode violation: assignment to 'arguments'" ) ) ;
1144+ let err_obj = crate :: core:: create_error ( mc, Some ( * proto_ptr) , msg) . map_err ( EvalError :: Js ) ?;
1145+ return Err ( EvalError :: Throw ( err_obj, None , None ) ) ;
1146+ }
1147+ // If we couldn't construct a SyntaxError instance for some reason, fall back
1148+ return Err ( EvalError :: Js ( raise_syntax_error ! (
1149+ "Strict mode violation: assignment to 'arguments'"
1150+ ) ) ) ;
1151+ }
1152+ }
1153+ }
1154+
10351155 let mut last_value = Value :: Undefined ;
10361156 for stmt in statements {
10371157 if let Some ( cf) = eval_res ( mc, stmt, & mut last_value, env, labels, own_labels) ? {
@@ -6033,7 +6153,7 @@ pub fn call_native_function<'gc>(
60336153
60346154 if name == "apply" || name == "Function.prototype.apply" {
60356155 let this = this_val. ok_or_else ( || EvalError :: Js ( raise_eval_error ! ( "Cannot call apply without this" ) ) ) ?;
6036- log:: debug !( "call_native_function: apply called on this={:?}" , this) ;
6156+ log:: trace !( "call_native_function: apply called on this={:?}" , this) ;
60376157 let new_this = args. first ( ) . cloned ( ) . unwrap_or ( Value :: Undefined ) ;
60386158 let arg_array = args. get ( 1 ) . cloned ( ) . unwrap_or ( Value :: Undefined ) ;
60396159
0 commit comments