Skip to content

Conversation

saghul
Copy link
Contributor

@saghul saghul commented Sep 6, 2024

The spec says HostMakeJobCallback has to be used on the callback: https://tc39.es/ecma262/multipage/managing-memory.html#sec-finalization-registry-cleanup-callback

That makes the following (arguably contrived) example run forever until memory is exhausted.

let count = 0; function main() { console.log(`main! ${++count}`); const registry = new FinalizationRegistry(() => { globalThis.foo = main(); }); registry.register([]); registry.register([]); return registry; } main(); console.log(count);

That is unlike V8, which runs 0 times. This can be explained by the difference in GC implementations and since FinRec makes GC observable, here we are!

Fixes: #432

@saghul saghul force-pushed the finrec-enqueue-job branch 5 times, most recently from 96f3f72 to 59d1dda Compare September 9, 2024 08:41
@saghul
Copy link
Contributor Author

saghul commented Sep 9, 2024

@bnoordhuis THis one should be ready now. I had to dig deep, so pl let me know what you think!

The spec says HostMakeJobCallback has to be used on the callback: https://tc39.es/ecma262/multipage/managing-memory.html#sec-finalization-registry-cleanup-callback That makes the following (arguably contrived) example run forever until memory is exhausted. ```js let count = 0; function main() { console.log(`main! ${++count}`); const registry = new FinalizationRegistry(() => { globalThis.foo = main(); }); registry.register([]); registry.register([]); return registry; } main(); console.log(count); ``` That is unlike V8, which runs 0 times. This can be explained by the difference in GC implementations and since FinRec makes GC observable, here we are! Fixes: #432
@saghul saghul force-pushed the finrec-enqueue-job branch from 59d1dda to 5cb2c21 Compare September 9, 2024 09:05
Copy link
Contributor

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@saghul saghul merged commit 61c8fe6 into master Sep 9, 2024
50 checks passed
@saghul saghul deleted the finrec-enqueue-job branch September 9, 2024 09:32
Comment on lines +53325 to 53332
if (!rt->in_free && (!JS_IsObject(fre->held_val) || JS_IsLiveObject(rt, fre->held_val))) {
JSValue args[2];
args[0] = frd->cb;
args[1] = fre->held_val;
JS_EnqueueJob(frd->ctx, js_finrec_job, 2, args);
}
JS_FreeValueRT(rt, fre->token);
js_free_rt(rt, fre);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to cause #648 and now that I'm looking at it more closely, I believe a spot a bug:

If the branch is not taken (i.e. no job is enqueued), shouldn't it JS_FreeValueRT(rt, fre->held_val)? fre is freed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly yeah. The object might not be live so I think we need to check for that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Figured it out just now: it should call JS_FreeValueRT(rt, fre->held_val) because JS_EnqueueJob increments the ref count, and js_finrec_job should not call JS_FreeValue(ctx, argv[1]). Pull request incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants