mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: for-await-of 同步迭代器 return() 忽略路径补异常值槽配对
This commit is contained in:
@@ -145,7 +145,9 @@ const ASFS_INNER_PROP: &str = "__oxide_asfs_inner__";
|
||||
/// # 参数
|
||||
/// - `inner`:内层同步迭代器(关闭目标)。
|
||||
/// - `result`:内层同步方法调用结果(`Err` 为调用抛出的字符串展平文本)。
|
||||
fn continue_async_from_sync(vm: &mut Vm, inner: JsValue, result: Result<JsValue, String>, close_on_rejection: bool) -> NativeResult {
|
||||
fn continue_async_from_sync(
|
||||
vm: &mut Vm, inner: JsValue, result: Result<JsValue, String>, close_on_rejection: bool,
|
||||
) -> NativeResult {
|
||||
let (promise, resolve, reject) = vm.new_promise_capability();
|
||||
let reject_with = |vm: &mut Vm, exc: JsValue| {
|
||||
if close_on_rejection {
|
||||
@@ -224,7 +226,10 @@ fn close_sync_iterator(vm: &mut Vm, inner: JsValue) {
|
||||
Err(_) => return,
|
||||
};
|
||||
if oxide_builtins::iterator::is_callable(return_fn) {
|
||||
// return() 的抛错被忽略,其值不得外泄进槽覆盖在途异常。
|
||||
let saved_uncaught = vm.last_uncaught_value.take();
|
||||
let _ = vm.call_function_sync(return_fn, inner, &[]);
|
||||
vm.last_uncaught_value = saved_uncaught;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,3 +228,54 @@ fn nested_inline_map_rest_poisoned_throws() {
|
||||
"true"
|
||||
);
|
||||
}
|
||||
|
||||
/// 复现 AsyncFromSyncIterator 的 valueWrapper reject 结算路径(close_sync_iterator
|
||||
/// 调用户 return() 抛真值):return() 的抛错被忽略后其值不得残留进槽——异常逃逸
|
||||
/// 出异步帧(resume_async 经槽恢复原值时取到残留 `true`)拒绝原因被污染。
|
||||
/// return() 只在 reject-close 第一次调用时抛错,IteratorClose 转发不抛,
|
||||
/// 保证残留之后没有新写槽覆盖。
|
||||
#[test]
|
||||
fn sync_iterator_return_throw_no_slot_pollution() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"var threw = false;\
|
||||
var inner = {\
|
||||
next() { throw 'x'; },\
|
||||
return() { if (!threw) { threw = true; throw true; } return { done: true }; } };\
|
||||
var iterable = { [Symbol.iterator]() { return inner; } };\
|
||||
async function f() { for await (var y of iterable) {} }\
|
||||
f()"
|
||||
),
|
||||
"<rejected \"x\">"
|
||||
);
|
||||
}
|
||||
|
||||
/// 回归:聚合迭代器关闭(close_agg_iterator)遇迭代抛错时调用户 return() 抛真值,
|
||||
/// 拒绝原因保持迭代抛出的原异常,不得被 return() 的 `true` 替换。
|
||||
#[test]
|
||||
fn agg_iterator_return_throw_no_slot_pollution() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"var inner = { next() { throw 'x'; }, return() { throw true; } };\
|
||||
var iterable = { [Symbol.iterator]() { return inner; } };\
|
||||
Promise.all(iterable).then(function () {}, function (e) { return e === true ? 'polluted:true' : e; })"
|
||||
),
|
||||
"\"x\""
|
||||
);
|
||||
}
|
||||
|
||||
/// 回归:Array.from 迭代输入抛错时 close_iterator 仍调用 return()(记录日志),
|
||||
/// 且迭代抛出的原异常优先于 return() 的返回值。
|
||||
#[test]
|
||||
fn array_from_iterator_close_original_error_wins() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"var log = '';\
|
||||
var inner = { next() { throw 'x'; }, return() { log += 'closed'; return {}; } };\
|
||||
var iterable = { [Symbol.iterator]() { return inner; } };\
|
||||
try { Array.from(iterable); } catch (e) { log += ':' + e; }\
|
||||
log"
|
||||
),
|
||||
"\"closed:x\""
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user