Skip to content

fix: Add maxBuffer option and enforce MAX_STRING_LENGTH on stdout and stderr by default [EXP-02]#55

Merged
kitten merged 7 commits into
mainfrom
@kitten/fix/unbounded-buffers
May 19, 2026
Merged

fix: Add maxBuffer option and enforce MAX_STRING_LENGTH on stdout and stderr by default [EXP-02]#55
kitten merged 7 commits into
mainfrom
@kitten/fix/unbounded-buffers

Conversation

@kitten
Copy link
Copy Markdown
Member

@kitten kitten commented May 15, 2026

Summary

Note

This attempts to avoid breaking changes, and is hand-written, since it's a thin line to walk, that didn't lead LLMs to write clean code. It's still LLM reviewed though

The string captured for stdout and stderr implicitly stringifies chunks, which can crash the process in two ways:

  • the maximum string length can be exceeded by this concatenation
  • the process memory can be exhausted with huge outputs from a command

By default, we should be enforcing the MAX_STRING_LENGTH. Existing calls of spawnAsync will now enforce this limit and will issue an error with the truncated strings when this limit is exceeded. The stdout and stderr strings are built lazily. The error we throw for this case will carry the truncated outputs.

When maxBuffer is set explicitly, we enforce this limit explicitly and reject the spawnAsync promise explicitly.

This was done to limit disruption to downstream consumers. However, it's still necessary for us to update call-sites that are uncontrolled/unbounded with an explicit maxBuffer, if we're calling spawnAsync on any process that:

  • is user-controlled/uncontrolled (can force a crash)
  • can produce huge outputs that can still cause memory to be consumed eagerly

Set of changes

  • Add maxBuffer option that, if set, rejects with a code: 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER' error when the buffer size is exceeded
  • Collect sliding chunk window for stdout and stderr chunks
    • Note: This also fixes byte encoding errors since we concatenate later before stringifying
  • Add lazy stdout and stderr getters that build the output string
    • When maxBuffer is not set explicitly, they may error lazily when the maximum size is reached now, which would've previously resulted in the max string length being exceeded accidentally during concatenation
  • Drive-by fix: Fix completionListener not being attached to exit when stdio is ignored and ignoreStdio isn't true

kitten added a commit to expo/expo that referenced this pull request May 18, 2026
…wn-async` [EXP-60] (#45891)

## Summary

Related to / Overlaps with #45836 

The use of `shell` for Windows is easily externally controllable, and
that's an unnecessary risk, which `@expo/spawn-async` mitigates. This
will also mean it benefits from other fixes, e.g.
expo/spawn-async#55, or existing mitigations.

# Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
@kitten kitten mentioned this pull request May 18, 2026
@kitten kitten merged commit 0a6de17 into main May 19, 2026
3 checks passed
@kitten kitten deleted the @kitten/fix/unbounded-buffers branch May 19, 2026 15:44
Comment thread src/spawnAsync.ts
Comment thread src/spawnAsync.ts
kitten added a commit that referenced this pull request May 19, 2026
Co-authored-by: James Ide <ide@expo.dev>
@kitten
Copy link
Copy Markdown
Member Author

kitten commented May 19, 2026

Checking against expo/expo CI here: expo/expo#45998
I'd expect to see zero failures, but better to be safe than sorry

kitten added a commit to expo/expo that referenced this pull request May 19, 2026
## Summary

See: expo/spawn-async#55

## Checklist

<!--
Please check the appropriate items below if they apply to your diff.
-->

- [x] I added a `changelog.md` entry and rebuilt the package sources
according to [this short
guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting)
- [ ] This diff will work correctly for `npx expo prebuild` & EAS Build
(eg: updated a module plugin).
- [ ] Conforms with the [Documentation Writing Style
Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants