Skip to content

FinalizationRegistry resource leak? #648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bnoordhuis opened this issue Nov 6, 2024 · 7 comments · Fixed by #649 or #656
Closed

FinalizationRegistry resource leak? #648

bnoordhuis opened this issue Nov 6, 2024 · 7 comments · Fixed by #649 or #656
Labels
bug Something isn't working

Comments

@bnoordhuis
Copy link
Contributor

Opening so I don't forget.

There seems to be a leak caused by FinalizationRegistry. Apply this diff:

diff --git a/tests/test_builtin.js b/tests/test_builtin.js
index 4c29503..57c77ab 100644
--- a/tests/test_builtin.js
+++ b/tests/test_builtin.js
@@ -1047,6 +1047,7 @@ test_generator();
 test_proxy_iter();
 test_proxy_is_array();
 test_finalization_registry();
+throw "boom";
 test_exception_source_pos();
 test_function_source_pos();
 test_exception_prepare_stack();

And then:

$ build/qjs tests/test_builtin.js
boom
qjs: /home/bnoordhuis/src/quickjs/quickjs.c:2109: JS_FreeRuntime: Assertion `list_empty(&rt->gc_obj_list)' failed.
Aborted (core dumped)

The assert does not trigger when you throw before the call to test_finalization_registry.

@bnoordhuis bnoordhuis added the bug Something isn't working label Nov 6, 2024
@bnoordhuis
Copy link
Contributor Author

More minimal example:

let finrec = new FinalizationRegistry(v => {})
finrec.register({}, {}) // primitive value works okay
throw "boom"

bnoordhuis added a commit to bnoordhuis/quickjs that referenced this issue Nov 6, 2024
No test because I can only get it to trigger with qjs, not run-test262,
but the problem is that we need to run FinalizationRegistry finalizers
before asserting no objects remain.

Fixes: quickjs-ng#648
@bnoordhuis
Copy link
Contributor Author

I still trigger that assert from time to time... reopening.

@bnoordhuis bnoordhuis reopened this Nov 6, 2024
@bnoordhuis
Copy link
Contributor Author

bnoordhuis commented Nov 6, 2024

Note how this now works:

let finrec = new FinalizationRegistry(v => {})
let object = {}
finrec.register(object, {})
throw "boom"

But this still asserts:

let finrec = new FinalizationRegistry(v => {})
finrec.register({}, {})
throw "boom"

As does this:

let finrec = new FinalizationRegistry(v => {})
let object = {}
finrec.register(object, {})
object = undefined
throw "boom"

js_finrec_finalizer only runs runs in the first case.

@bnoordhuis
Copy link
Contributor Author

bnoordhuis commented Nov 6, 2024

Oh, and: setting finrec = undefined also avoids the assert. - no wait, still asserts

@saghul
Copy link
Contributor

saghul commented Nov 6, 2024

If you enable leak dumping, what do you see? (Not at the computer now)

@bnoordhuis
Copy link
Contributor Author

Right, I didn't mention that but it's the heldValue (second argument) that leaks.

@bnoordhuis
Copy link
Contributor Author

I tracked it down to a regression beginning with commit 61c8fe6.

bnoordhuis added a commit to bnoordhuis/quickjs that referenced this issue Nov 6, 2024
Introduced in commit 61c8fe6 from last month that moved the callback
into the job queue:

1. It leaked `fre->held_val` when no job was enqueued

2. It fumbled the reference count when enqueuing; JS_EnqueueJob already
   takes care of incrementing and decrementing it

Reverts commit 0a70623 from earlier today because that didn't turn out
to be a complete fix.

Fixes: quickjs-ng#648
bluesky950520 pushed a commit to bluesky950520/quickjs that referenced this issue Mar 14, 2025
No test because I can only get it to trigger with qjs, not run-test262,
but the problem is that we need to run FinalizationRegistry finalizers
before asserting no objects remain.

Fixes: quickjs-ng/quickjs#648
bluesky950520 pushed a commit to bluesky950520/quickjs that referenced this issue Mar 14, 2025
Introduced in commit 61c8fe6 from last month that moved the callback
into the job queue:

1. It leaked `fre->held_val` when no job was enqueued

2. It fumbled the reference count when enqueuing; JS_EnqueueJob already
   takes care of incrementing and decrementing it

Reverts commit 0a70623 from earlier today because that didn't turn out
to be a complete fix.

Fixes: quickjs-ng/quickjs#648
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants