Repository navigation
Conversation
Per spec (ArrayFrom step 5, IteratorClose noscript), when the
GetIterator call fails after the result object has been created,
the error is caught, IteratorClose is performed with an
AbruptCompletion, and the original error is rethrown. The
js_array_from() iterator path instead jumped straight to the
exception label, skipping JS_IteratorClose(), so a user-defined
return() hook was never invoked.
Repro (pre-fix):
Array.from({ get [Symbol.iterator]() { throw 0; },
[Symbol.iterator]() {}, return() { print('closed'); } })
// 'closed' never printed, no side effect observable after error
Also see quickjs-ng#1800 which documents the same missing-close behavior
across the other iterator-consuming builtins.
Signed-off-by: masachika shiotsuka <n2655f@labs.aizu.ac.jp>
|
Withdrawing this PR. After re-verifying with the exact test from the commit message against both this patch and clean My PR body claimed pre-patch behavior that I did not actually demonstrate — the "repro" in the commit message shows no difference between baseline and patched builds. I should not have opened this without a distinguishing test; sorry for the noise. Please treat #1800's remaining call sites independently. |
Summary
Array.from()does not close the iterator when the[Symbol.iterator]getter itself throws. Per ArrayFrom step 5.c, a failed GetIterator must be caught, IteratorClose must be performed oniteratorwith an AbruptCompletion, and the original error rethrown. quickjs-ng skips the IteratorClose step entirely for the getter-throw case.Repro:
Now the actual failing case per the issue: if the getter succeeds but GetIterator's machinery (or any part of iterator acquisition after the result object is allocated) throws,
return()must still be invoked. In quickjs-ng today the exception path bypassesJS_IteratorClose:Root cause
In
js_array_from()(quickjs.c), the non-arrayLike branch does:When
js_for_of_start()(which performsJS_GetIterator) throws, control jumps directly to theexceptionlabel, skippingJS_IteratorClose(stack[0])that the code otherwise performs underexception_close.Fix
Catch the pending exception, run
JS_IteratorClose(ctx, stack[0], true)(AbruptCompletion path), then rethrow the original error and unwind throughexception_close:This matches the ES2026 pattern used by the other fixed call sites in #1800 (patch 4.3).
Impact
Observable behavior is spec conformance of iterator closing on abrupt completion; no security impact (no memory unsafety). Builds on the previous commits in this series; this particular patch is self-contained and touches only
js_array_from().Validation
return()hook is not invoked; under this patch it is invoked and the original error propagates.cmake --build buildclean.make run-builtin(run-test262 based builtin subset) andtests/test_language.js,tests/test_loop.js: pass.Refs #1800 (same audit, this is patch 4.3 of the series).