fix(js): run string timer handlers as global-scope scripts at fire time
A string setTimeout/setInterval handler was compiled with new Function(fn) at scheduling time. That diverged from the HTML spec in two ways: top-level var/function declarations in the body stayed local to the compiled function instead of becoming globals, and a syntax error was caught eagerly at scheduling and turned into a silent no-op (that still returned a timer id) rather than surfacing when the timer fires. Defer string handlers to fire-time indirect eval ((0, eval)(src)), which runs in the true global scope like a classic script, so declarations become global and a SyntaxError is thrown when the timer elapses. Matches the dynamic-script path, which already uses indirect eval for the same reason. Function handlers are unchanged. Fixes #558
This commit is contained in:
1 parent
f0541f40a4
commit
452cc8554f
2 files changed
+29
-1
No files matched your search
@@ -1330,6 +1330,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn string_timeout_declarations_reach_global_scope() {
|
||||
// A string timer handler runs as a classic script in global scope, so a
|
||||
// top-level var/function declaration in it becomes a global. new Function()
|
||||
// kept those declarations local to the compiled function, so they never
|
||||
// reached globalThis.
|
||||
let mut rt = setup_runtime("<html><body></body></html>");
|
||||
rt.evaluate(
|
||||
"setTimeout('var __leaked = 42; function __leakedFn(){ return 7; }', 0)",
|
||||
)
|
||||
.unwrap();
|
||||
rt.run_event_loop_bounded(100).await.unwrap();
|
||||
let v = rt
|
||||
.evaluate(
|
||||
"String(globalThis.__leaked) + '|' + (typeof globalThis.__leakedFn === 'function' ? globalThis.__leakedFn() : 'missing')",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(v, serde_json::json!("42|7"));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn string_interval_handler_repeats_and_can_clear_itself() {
|
||||
let mut rt = setup_runtime("<html><body></body></html>");
|
||||
|
||||
Reference in new issue
Block a user