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

"inconvenient" stack overflow when using spread operator - changing stack size does not work #16870

Closed
olydis opened this issue Nov 7, 2017 · 7 comments
Labels
question Issues that look for answers. v8 engine Issues and PRs related to the V8 dependency.

Comments

@olydis
Copy link

olydis commented Nov 7, 2017

  • Version: 7.10 (or most likely earlier) until 9.1.0 as far as I can tell
  • Platform: Windows 10
  • Subsystem: x64

Happy about recent ES features, we did stuff like someArray.push(...someOtherArray) which turns out to be problematic for large someOtherArray (say, 1 million elements), causing a stack overflow presumably because of the huge number of "arguments". There is the obvious workaround of loop-pushing (...with some helper method, since it's ugly to do that in tons of places), but given that the spread array doesn't even have too large for this to happen, I was also investigating stack size. I read about the --stack-size/--stack_size parameter, but setting that to anything significantly larger than 1000 on my Windows box caused the process to just silently crash instead of getting the nice stack overflow error.

I'm not expecting any magic, the error and its reason makes sense to me, I just wondered:

  • is there a plan regarding enabling scenarios like push(...LARGE_ARRAY) since I assume that's the pattern people will happily use these days, unaware of the caveat
  • is there any plan/way to support larger stacks on Windows?

Now that I wrote this, I think maybe these questions make more sense on the V8 side, but maybe you have valuable insights/ideas to share 🙂

@addaleax addaleax added question Issues that look for answers. v8 engine Issues and PRs related to the V8 dependency. labels Nov 7, 2017
@addaleax
Copy link
Member

addaleax commented Nov 7, 2017

I read about the --stack-size/--stack_size parameter, but setting that to anything significantly larger than 1000 on my Windows box caused the process to just silently crash instead of getting the nice stack overflow error.

--stack-size doesn’t let you set the stack size; it tells V8 what to assume for the usable stack size. So when you set it to a value that exceed the actual size, V8 just runs past the end of the stack and crashes.

/cc @nodejs/v8 for the question about .push(...array)

@olydis
Copy link
Author

olydis commented Nov 7, 2017

Thanks for the clarification about stack size - it felt that way given that it crashed silently 👍

@hashseed
Copy link
Member

hashseed commented Nov 8, 2017

This is working as intended. The spread operator simply pushes all array elements onto the stack. You essentially have the same restrictions as Function.prototype.apply. You are better served doing something like

for (let e of someOtherArray) someArray.push(e)

@bmeurer
Copy link
Member

bmeurer commented Nov 8, 2017

How about using array spread instead?

someArray = [...someArray, ...someOtherArray];

@psmarshall
Copy link
Contributor

Yeah this is one of the ways in which spread calls are surprising in JS. There is some more discussion about it on this bug.

  • Is there a plan for allowing larger spreads?

Basically, no. In the bug above I mention a few things we thought about to enable that, but the benefits are kind of unclear and it won't be particularly easy. Other JS engines would also need to do the same thing to enable spread to be used widely in this way. I guess for node you know much more about the JS engine you are using, so it would be more useful there.

Unfortunately, the best advice I can give is to avoid spread calls unless you know something about the length of your array and thus the stack space it will use. It is still useful for some other things particularly in combination with rest parameters, but this style where you call Array push or Math max/min is a bit dangerous for exactly the reason you describe.

@olydis
Copy link
Author

olydis commented Nov 8, 2017

@hashseed @bmeurer Absolutely, note that this was not about how to work around this issue, but whether there are plans to support large spreads in calls. We used them "accidentally" since they are super convenient and while it makes perfect sense that you're exploding the stack, it's easy to miss. Also, tons of online resources will suggest stuff like that as the "ES6-way" of doing things, so I was curious whether there are plans to, say, implement calls differently in the future to work around that.

@psmarshall Thanks for the insights, that makes perfect sense!

@olydis olydis closed this as completed Nov 8, 2017
ivanstanev added a commit to snyk/dep-graph that referenced this issue Oct 23, 2019
A customer cannot scan their project with a supposedly very large dependency graph because as soon as it reaches our back-end, we get a stack overflow error. It was identified that the error is due to the combination of Array.push() and the spread operator.

For reference: nodejs/node#16870

To reproduce, create an array of size 2^17 then do [].push(...myArray);.

This fix replaces all uses of push() and spread with a simple loop.
ivanstanev added a commit to snyk/dep-graph that referenced this issue Oct 24, 2019
A customer cannot scan their project with a supposedly very large dependency graph because as soon as it reaches our back-end, we get a stack overflow error. It was identified that the error is due to the combination of Array.push() and the spread operator.

For reference: nodejs/node#16870

To reproduce, create an array of size 2^17 then do [].push(...myArray);.

This fix replaces all uses of push() and spread with a simple loop.
darscan pushed a commit to snyk/dep-graph that referenced this issue Oct 24, 2019
A customer cannot scan their project with a supposedly very large
dependency graph because as soon as it reaches our back-end,
we get a stack overflow error. It was identified that the error is
due to the combination of Array.push() and the spread operator.

For reference: nodejs/node#16870

To reproduce, create an array of size 2^17 then do [].push(...myArray);

This fix replaces all uses of push() and spread with a simple loop.
npenin added a commit to npenin/akala that referenced this issue Oct 2, 2021
jstasiak pushed a commit to lune-climate/ts-results-es that referenced this issue Apr 24, 2024
Howdy! I'm bringing this PR over from the decidedly dead
vultix/ts-results repo.

This PR adds non-spread variants of `Result.all` and `Result.any`
which should be preferred over the parameter spread variants. For
instances where `Result.all` or `Result.any` are invoked with very
large arrays, the spread operation could lead to stack overflows
(nodejs/node#16870 (comment)). 

Additionally, speaking from personal experience in an enterprise
environment; the usage of `Result.all` via a spread array
(`Result.all(...myResults)`) grossly exceeds the usage of
`Result.all` with multiple parameters. I'd imagine this is the same
for others as well.

This new behavior has been added as an overload of `Result.all`
to offer backwards compatibility for those spreading arrays in, or
passing each argument individually. Though based on the stack
overflow issue mentioned above, I'd recommend users migrate
from array spreading to just passing the array.
varungandhi-src added a commit to sourcegraph/sourcegraph-public-snapshot that referenced this issue Jul 25, 2024
Using the spread operator with large arrays can trigger a
stack overflow in Chrome/V8. For example, see:
- nodejs/node#16870

In a highlighting context, we can have 10k-100k occurrences
in a file, so let's avoid using the spread operator.

Fixes https://linear.app/sourcegraph/issue/GRAPH-772

## Test plan

Manually tested against sample file.

![](https://github.com/user-attachments/assets/e096c664-063e-44ed-a991-72629af36651)

## Changelog

- Fixes a Chrome-specific stack overflow when highlighting large files.
sourcegraph-release-bot pushed a commit to sourcegraph/sourcegraph-public-snapshot that referenced this issue Jul 25, 2024
Using the spread operator with large arrays can trigger a
stack overflow in Chrome/V8. For example, see:
- nodejs/node#16870

In a highlighting context, we can have 10k-100k occurrences
in a file, so let's avoid using the spread operator.

Fixes https://linear.app/sourcegraph/issue/GRAPH-772

## Test plan

Manually tested against sample file.

![](https://github.com/user-attachments/assets/e096c664-063e-44ed-a991-72629af36651)

## Changelog

- Fixes a Chrome-specific stack overflow when highlighting large files.

(cherry picked from commit 2644e24)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Issues that look for answers. v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

No branches or pull requests

6 participants