LibJS: Do more comprehensive check if next() fast path is possible

Before this change each built-in iterator object has a boolean
`m_next_method_was_redefined`. If user code later changed the iterator’s
prototype (e.g. `Object.setPrototypeOf()`), we still believed the
built-in fast-path was safe and skipped the user supplied override,
producing wrong results.

With this change
`BuiltinIterator::as_builtin_iterator_if_next_is_not_redefined()` looks
up the current `next` property and verifies that it is still the
built-in native function.
This commit is contained in:
Aliaksandr Kalenik 2025-06-01 18:44:18 +02:00 committed by Alexander Kalenik
commit 285bc005cb
Notes: github-actions[bot] 2025-06-01 22:16:38 +00:00
25 changed files with 168 additions and 98 deletions

View file

@ -0,0 +1,64 @@
describe("redefine next() in built in iterators", () => {
test("override next() on individual Array iterator via setPrototypeOf", () => {
const iter = [1, 2, 3][Symbol.iterator]();
const originalNext = iter.next;
let count = 0;
const newProto = {
next(...args) {
count++;
return originalNext.apply(this, args);
},
[Symbol.iterator]() {
return this;
},
};
Object.setPrototypeOf(iter, newProto);
for (const v of iter) {
}
expect(count).toBe(4);
});
test("override next() on individual Map iterator via setPrototypeOf", () => {
const map = new Map([
[1, 1],
[2, 2],
[3, 3],
]);
const iter = map.values();
const originalNext = iter.next;
let count = 0;
const newProto = {
next(...args) {
count++;
return originalNext.apply(this, args);
},
[Symbol.iterator]() {
return this;
},
};
Object.setPrototypeOf(iter, newProto);
for (const v of iter) {
}
expect(count).toBe(4);
});
test("override next() on individual Set iterator via setPrototypeOf", () => {
const set = new Set([1, 2, 3]);
const iter = set.values();
const originalNext = iter.next;
let count = 0;
const newProto = {
next(...args) {
count++;
return originalNext.apply(this, args);
},
[Symbol.iterator]() {
return this;
},
};
Object.setPrototypeOf(iter, newProto);
for (const v of iter) {
}
expect(count).toBe(4);
});
});