Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack underflow in generator function #717

Open
bptato opened this issue Nov 21, 2024 · 6 comments
Open

Stack underflow in generator function #717

bptato opened this issue Nov 21, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@bptato
Copy link
Contributor

bptato commented Nov 21, 2024

$ cat test.js
function* a() {
  for (var x of yield y)
    ;
}
$ node test.js
$ qjs test.js
InternalError: stack underflow (op=111, pc=9)

FWIW, bellard/quickjs exhibits the same behavior.

@bnoordhuis
Copy link
Contributor

Parse error, most likely, and probably not super difficult to fix, but I'm curious: what is the expected result of a().next()?

It's my understanding that even when y is defined and yields e.g. an array, the spec still only allows throwing an exception because the expression yield y is an intermediate value that isn't itself iterable.

@bnoordhuis bnoordhuis added the bug Something isn't working label Nov 21, 2024
@bptato
Copy link
Contributor Author

bptato commented Nov 21, 2024

what is the expected result of a().next()?

I'm curious as well :P it's a reduced test case from a web app.
Node seems to first yield y, and only throws on the second next().

@saghul
Copy link
Contributor

saghul commented Nov 22, 2024

Node seems to first yield y, and only throws on the second next().

Really? Node, Deno and Bun all work for me. I guess because we are not calling a so it's just parsing?

@bnoordhuis
Copy link
Contributor

Yes. It's not an early parse error, just a nonsensical construct, AFAICT.

@bnoordhuis
Copy link
Contributor

BTW, I figured out the cause (unfortunate intermingling of yield + if_false vs. nip_catch), just need to think of an elegant way to fix it.

js_parse_assign_expr2 emits the yield + if_false, and calls emit_return (emits the nip_catch) in between.

@bptato
Copy link
Contributor Author

bptato commented Nov 22, 2024

Yes. It's not an early parse error, just a nonsensical construct, AFAICT.

Context: I was trying to load bluesky with my browser, and QJS output a stack underflow. I bisected the JS, and found the offending code segment (inside a generator function):

if (null != l && l.pages)
  for (var c of null == l ? void 0 : l.pages)
    for (var d of (c.list.creator.did === t && (yield c.list.creator), c.items))
      d.subject.did === t && (yield d.subject)

which I believe maps to this.
So originally it's just a transpiler collapsing an if such that yield happens to end up inside the expression (?) that evaluates to an iterable. I guess a more faithful test case is:

function* a() {
  for (var x of (yield {}, []))
    ;
}
var z = a();
z.next();
z.next();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants