Skip to content

Commit 25b5e70

Browse files
leegn4asaghul
authored andcommitted
Fix Iterator.concat reentrancy guard
1 parent 95fc452 commit 25b5e70

2 files changed

Lines changed: 86 additions & 17 deletions

File tree

quickjs.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43468,42 +43468,43 @@ static JSValue js_iterator_concat_next(JSContext *ctx, JSValueConst this_val,
4346843468
return JS_EXCEPTION;
4346943469
if (it->running)
4347043470
return JS_ThrowTypeError(ctx, "already running");
43471+
it->running = true;
4347143472
next:
4347243473
if (it->index >= it->count) {
4347343474
*pdone = true;
43474-
return JS_UNDEFINED;
43475+
val = JS_UNDEFINED;
43476+
goto done;
4347543477
}
4347643478
obj = &it->values[it->index + 0];
4347743479
meth = &it->values[it->index + 1];
4347843480
iter = it->iter;
4347943481
if (JS_IsUndefined(iter)) {
4348043482
iter = JS_GetIterator2(ctx, *obj, *meth);
4348143483
if (JS_IsException(iter))
43482-
return JS_EXCEPTION;
43484+
goto fail;
4348343485
it->iter = iter;
4348443486
}
4348543487
next = it->next;
4348643488
if (JS_IsUndefined(next)) {
4348743489
next = JS_GetProperty(ctx, iter, JS_ATOM_next);
4348843490
if (JS_IsException(next))
43489-
return JS_EXCEPTION;
43491+
goto fail;
4349043492
it->next = next;
4349143493
}
43492-
it->running = true;
4349343494
item = JS_IteratorNext2(ctx, iter, next, 0, NULL, &done);
43494-
it->running = false;
4349543495
if (JS_IsException(item))
43496-
return JS_EXCEPTION;
43496+
goto fail;
4349743497
if (!done) {
4349843498
*pdone = false;
43499-
return item;
43499+
val = item;
43500+
goto done;
4350043501
}
4350143502
// done==1 means really done, done==2 means "unknown, inspect object"
4350243503
if (done == 2) {
4350343504
val = JS_GetProperty(ctx, item, JS_ATOM_done);
4350443505
if (JS_IsException(val)) {
4350543506
JS_FreeValue(ctx, item);
43506-
return JS_EXCEPTION;
43507+
goto fail;
4350743508
}
4350843509
done = JS_ToBoolFree(ctx, val);
4350943510
}
@@ -43521,7 +43522,12 @@ static JSValue js_iterator_concat_next(JSContext *ctx, JSValueConst this_val,
4352143522
val = JS_GetProperty(ctx, item, JS_ATOM_value);
4352243523
JS_FreeValue(ctx, item);
4352343524
*pdone = false;
43525+
done:
43526+
it->running = false;
4352443527
return val;
43528+
fail:
43529+
val = JS_EXCEPTION;
43530+
goto done;
4352543531
}
4352643532

4352743533
static JSValue js_iterator_concat_return(JSContext *ctx, JSValueConst this_val,

tests/bug1368.js

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,72 @@
1-
let it;
2-
const evil = {
3-
[Symbol.iterator]() {
4-
it.return();
5-
return [][Symbol.iterator]();
6-
}
7-
};
8-
it = Iterator.concat(evil);
9-
it.next();
1+
import { assert, assertThrows } from "./assert.js";
2+
3+
function test_symbol_iterator_reentry() {
4+
let it;
5+
let calls = 0;
6+
const evil = {
7+
[Symbol.iterator]() {
8+
calls++;
9+
assertThrows(TypeError, () => it.return());
10+
return [][Symbol.iterator]();
11+
},
12+
};
13+
14+
it = Iterator.concat(evil);
15+
const result = it.next();
16+
assert(calls, 1);
17+
assert(result.done, true);
18+
assert(result.value, undefined);
19+
}
20+
21+
function test_next_getter_reentry() {
22+
let it;
23+
let calls = 0;
24+
const evil = {
25+
[Symbol.iterator]() {
26+
return {
27+
get next() {
28+
calls++;
29+
assertThrows(TypeError, () => it.return());
30+
return () => ({ done: true, value: 1 });
31+
},
32+
};
33+
},
34+
};
35+
36+
it = Iterator.concat(evil);
37+
const result = it.next();
38+
assert(calls, 1);
39+
assert(result.done, true);
40+
assert(result.value, undefined);
41+
}
42+
43+
function test_value_getter_reentry() {
44+
let it;
45+
let calls = 0;
46+
const evil = {
47+
[Symbol.iterator]() {
48+
return {
49+
next() {
50+
return {
51+
done: false,
52+
get value() {
53+
calls++;
54+
assertThrows(TypeError, () => it.return());
55+
return 1;
56+
},
57+
};
58+
},
59+
};
60+
},
61+
};
62+
63+
it = Iterator.concat(evil);
64+
const result = it.next();
65+
assert(calls, 1);
66+
assert(result.done, false);
67+
assert(result.value, 1);
68+
}
69+
70+
test_symbol_iterator_reentry();
71+
test_next_getter_reentry();
72+
test_value_getter_reentry();

0 commit comments

Comments
 (0)