Repository: denoland/deno
Pull request: fix(ext/web): fix `AbortSignal.timeout()` leak

<!--
Before submitting a PR, please read https://docs.deno.com/runtime/manual/references/contributing

1. Give the PR a descriptive title.

  Examples of good title:
    - fix(std/http): Fix race condition in server
    - docs(console): Update docstrings
    - feat(doc): Handle nested reexports

  Examples of bad title:
    - fix #7123
    - update docs
    - fix bugs

2. Ensure there is a related issue and it is referenced in the PR text.
3. Ensure there are tests that cover the changes.
4. Ensure `cargo test` passes.
5. Ensure `./tools/format.js` passes without changing files.
6. Ensure `./tools/lint.js` passes.
7. Open as a draft PR if your work is still in progress. The CI won't run
   all steps, but you can add '[ci]' to a commit message to force it to.
8. If you would like to run the benchmarks on the CI, add the 'ci-bench' label.
-->

Fixes #20663.


Changed files:
filename: Cargo.lock
patch: @@ -1304,8 +1304,7 @@ dependencies = [
 [[package]]
 name = "deno_core"
 version = "0.289.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e22f78a33feec9a7b211253b0aefbb8cb3b0081483ee8cec7bd954c76ac072a"
+source = "git+https://github.com/denoland/deno_core#e0f203688ad98dd18cc079e48e9f2c318899519f"
 dependencies = [
  "anyhow",
  "bincode",
@@ -1763,8 +1762,7 @@ dependencies = [
 [[package]]
 name = "deno_ops"
 version = "0.165.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "063c6ab08f9275a958878ae54e470cc6ce16f81c1fef16129db0c99d46c5fd35"
+source = "git+https://github.com/denoland/deno_core#e0f203688ad98dd18cc079e48e9f2c318899519f"
 dependencies = [
  "proc-macro-rules",
  "proc-macro2",
@@ -5785,8 +5783,7 @@ dependencies = [
 [[package]]
 name = "serde_v8"
 version = "0.198.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "491380c88077b81b2390e5f0cc10f64860819ba03369bb154bb9e4a587b31a01"
+source = "git+https://github.com/denoland/deno_core#e0f203688ad98dd18cc079e48e9f2c318899519f"
 dependencies = [
  "num-bigint",
  "serde",

filename: Cargo.toml
patch: @@ -368,3 +368,6 @@ opt-level = 3
 opt-level = 3
 [profile.release.package.base64-simd]
 opt-level = 3
+
+[patch.crates-io]
+deno_core = { git = "https://github.com/denoland/deno_core" }

filename: ext/web/03_abort_signal.js
patch: @@ -3,7 +3,7 @@
 // @ts-check
 /// <reference path="../../core/internal.d.ts" />
 
-import { primordials } from "ext:core/mod.js";
+import { core, primordials } from "ext:core/mod.js";
 const {
   ArrayPrototypeEvery,
   ArrayPrototypePush,
@@ -33,7 +33,7 @@ import {
   listenerCount,
   setIsTrusted,
 } from "./02_event.js";
-import { refTimer, setTimeout, unrefTimer } from "./02_timers.js";
+import { clearTimeout, refTimer, unrefTimer } from "./02_timers.js";
 
 // Since WeakSet is not a iterable, WeakRefSet class is provided to store and
 // iterate objects.
@@ -118,14 +118,17 @@ class AbortSignal extends EventTarget {
     );
 
     const signal = new AbortSignal(illegalConstructorKey);
-    signal[timerId] = setTimeout(
+    signal[timerId] = core.queueSystemTimer(
+      undefined,
+      false,
+      millis,
       () => {
+        clearTimeout(signal[timerId]);
         signal[timerId] = null;
         signal[signalAbort](
           new DOMException("Signal timed out.", "TimeoutError"),
         );
       },
-      millis,
     );
     unrefTimer(signal[timerId]);
     return signal;

filename: tests/unit/timers_test.ts
patch: @@ -767,3 +767,11 @@ Deno.test({
     assert(result >= 1000);
   },
 });
+
+// Regression test for https://github.com/denoland/deno/issues/20663
+Deno.test({
+  name: "regression for #20663",
+  fn: () => {
+    AbortSignal.timeout(2000);
+  },
+});