Checkpoint before integration and package validation. Assisted-by: SurmAgent:unknown [read] [edit] [bash]
55 lines
1.3 KiB
JavaScript
55 lines
1.3 KiB
JavaScript
import * as std from "qjs:std";
|
|
// https://github.com/quickjs-ng/quickjs/issues/1318
|
|
// Heap use-after-free when FinalizationRegistry is part of a reference cycle.
|
|
// Run under ASAN.
|
|
|
|
// Test 1: held value is the FR itself (original PoC pattern)
|
|
{
|
|
let target = {};
|
|
let fr = new FinalizationRegistry(function() {});
|
|
fr.register(target, fr);
|
|
fr.ref = target;
|
|
target.ref = fr;
|
|
target = null;
|
|
fr = null;
|
|
std.gc();
|
|
}
|
|
|
|
// Test 2: callback is part of the cycle
|
|
{
|
|
let target = {};
|
|
let cb = function() {};
|
|
let fr = new FinalizationRegistry(cb);
|
|
fr.register(target, 42);
|
|
fr.ref = target;
|
|
target.ref = fr;
|
|
target.cb = cb;
|
|
target = null;
|
|
fr = null;
|
|
cb = null;
|
|
std.gc();
|
|
}
|
|
|
|
// Test 3: simplified real-world pattern (from issue comment)
|
|
{
|
|
class Registry {
|
|
#fr = new FinalizationRegistry(v => {});
|
|
set(key) {
|
|
const ref = new WeakRef(key);
|
|
this.#fr.register(key, {}, ref);
|
|
}
|
|
}
|
|
function Observer() {
|
|
this.targets = new Registry;
|
|
}
|
|
Observer.prototype.observe = function(target) {
|
|
this.targets.set(target);
|
|
target.subset = new Set;
|
|
target.subset.add(this);
|
|
}
|
|
let sample = {};
|
|
new Observer().observe(sample);
|
|
sample = null;
|
|
std.gc();
|
|
}
|