Skip to content

Commit 515dd24

Browse files
theanarkhtargos
authored andcommitted
lib: fix timer leak
PR-URL: #53337 Fixes: #53335 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Feng Yu <F3n67u@outlook.com> Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
1 parent cf375e7 commit 515dd24

File tree

4 files changed

+37
-6
lines changed

4 files changed

+37
-6
lines changed

lib/internal/timers.js

+12
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ const timerListQueue = new PriorityQueue(compareTimersLists, setPosition);
152152
// - value = linked list
153153
const timerListMap = { __proto__: null };
154154

155+
// This stores all the known timer async ids to allow users to clearTimeout and
156+
// clearInterval using those ids, to match the spec and the rest of the web
157+
// platform.
158+
const knownTimersById = { __proto__: null };
159+
155160
function initAsyncResource(resource, type) {
156161
const asyncId = resource[async_id_symbol] = newAsyncId();
157162
const triggerAsyncId =
@@ -550,6 +555,9 @@ function getTimerCallbacks(runNextTicks) {
550555
if (!timer._destroyed) {
551556
timer._destroyed = true;
552557

558+
if (timer[kHasPrimitive])
559+
delete knownTimersById[asyncId];
560+
553561
if (timer[kRefed])
554562
timeoutInfo[0]--;
555563

@@ -580,6 +588,9 @@ function getTimerCallbacks(runNextTicks) {
580588
} else if (!timer._idleNext && !timer._idlePrev && !timer._destroyed) {
581589
timer._destroyed = true;
582590

591+
if (timer[kHasPrimitive])
592+
delete knownTimersById[asyncId];
593+
583594
if (timer[kRefed])
584595
timeoutInfo[0]--;
585596

@@ -683,4 +694,5 @@ module.exports = {
683694
timerListQueue,
684695
decRefCount,
685696
incRefCount,
697+
knownTimersById,
686698
};

lib/timers.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const {
5252
active,
5353
unrefActive,
5454
insert,
55+
knownTimersById,
5556
} = require('internal/timers');
5657
const {
5758
promisify: { custom: customPromisify },
@@ -71,11 +72,6 @@ const {
7172
emitDestroy,
7273
} = require('internal/async_hooks');
7374

74-
// This stores all the known timer async ids to allow users to clearTimeout and
75-
// clearInterval using those ids, to match the spec and the rest of the web
76-
// platform.
77-
const knownTimersById = { __proto__: null };
78-
7975
// Remove a timer. Cancels the timeout and resets the relevant timer properties.
8076
function unenroll(item) {
8177
if (item._destroyed)

test/fixtures/source-map/output/source_map_throw_set_immediate.snapshot

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
Error: goodbye
77
at Hello (*uglify-throw-original.js:5:9)
88
at Immediate.<anonymous> (*uglify-throw-original.js:9:3)
9-
at process.processImmediate (node:internal*timers:478:21)
9+
at process.processImmediate (node:internal*timers:483:21)
1010

1111
Node.js *
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
// Flags: --expose-gc
3+
require('../common');
4+
const onGC = require('../common/ongc');
5+
6+
// See https://github.com/nodejs/node/issues/53335
7+
const poller = setInterval(() => {
8+
global.gc();
9+
}, 100);
10+
11+
let count = 0;
12+
13+
for (let i = 0; i < 10; i++) {
14+
const timer = setTimeout(() => {}, 0);
15+
onGC(timer, {
16+
ongc: () => {
17+
if (++count === 10) {
18+
clearInterval(poller);
19+
}
20+
}
21+
});
22+
console.log(+timer);
23+
}

0 commit comments

Comments
 (0)