fix(core): eliminate Windows fork bomb caused by recursive shim execution#41
Merged
Conversation
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Co-authored-by: Chris Krycho <hello@chriskrycho.com>
Co-authored-by: Chris Krycho <hello@chriskrycho.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #41 +/- ##
==========================================
+ Coverage 80.44% 80.53% +0.08%
==========================================
Files 105 105
Lines 10567 10629 +62
==========================================
+ Hits 8501 8560 +59
- Misses 2066 2069 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
…rrors Co-authored-by: Codex (GPT-5.3) <codex@openai.com> Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
e0f1d31 to
2c190f0
Compare
Signed-off-by: Chawye Hsu <su+git@chawyehsu.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This patch was submitted to upstream in PR volta-cli#1761 and had received code reviews, but obsoleted because of upstream becoming unmaintained. It was also applied in https://github.com/chawyehsu/volta/tree/staging
Details
Background
This PR was initially created to address a fork bomb issue observed on Windows. The root cause of this issue consists of two parts.
First, the existing
RECURSION_ENV_VARis always set to1and never incremented when volta/volta-shim spawning child processes, which makes a fork bomb possible. This environment variable should instead be incremented on each recursion and guarded by an upper limit. Once the limit is reached, the process should return an error and exit. For example, rustup implements a recursion guard with a limit of 201.Second, based on the first condition, a fork bomb could theoretically occur on all operating systems supported by Volta, yet in practice the issue only manifests on Windows. This discrepancy comes from a flaw in Volta’s
create_commandfunction used to spawn child processes.Child processes are created by passing the executable name into
create_command. AfterCommandis constructed, the Volta platform bin directory is appended to thePATHenvironment variable in the execution context. Differences in the implementation behavior ofcreate_commandlead to different outcomes across platforms.On Unix systems, the system call resolves the actual target executable through
PATHand executes it as expected. On Windows, however, executable lookup order may behave less intuitively. When the executable path is relative rather than absolute, Windows searches in the following order: current working directory (cwd), thenPATH.Because
Command::new("cmd.exe")is used, even though Rust’s standard library resolves the executable fromPATH, it only resolvescmd.exeitself. After thecmd.exeprocess is created, the system will prioritize searching for the actual target executable in the cwd ofcmd.exe(which is also the directory containing the parent Volta shim). As a result, resolution points back to the Volta shim itself, ultimately triggering a fork bomb.Why
Command::new("cmd.exe")/cmd.exe /CIn the PR I submitted to the upstream repository, volta-cli#1761 (comment) @charlespierce explained in detail why Volta originally adopted
cmd.exe /C: Rust'sCommandin std library does not reliably resolve.batand.cmdfiles, which are created and used by the Node.js runtime.The Fix
In the PR I submitted to the upstream repository, I introduced
which-rsto resolve and obtain the full path of the target executable beforeCommandis finally executed. A newCommandinstance is reconstructed using the resolved absolute path and executed accordingly. With this approach, I did not modify the existingcreate_commandimplementation that relies oncmd.exe /C.That was because Volta’s
Executors (such asToolCommand) invokecreate_commandduring::new(), completingCommandconstruction at executor initialization time. Without refactoring them, it is impossible to avoid a secondCommand::newinvocation. To address this, I separated the related refactoring work into #44 for easier historical tracking.By leveraging the third-party
which-rslibrary, we are able to reliably resolve.batand.cmdfiles, making it possible to remove the dependency oncmd.exe /C.which-rsresolves target executables using the systemPATHEXTenvironment variable.With the introduction of a recursion limit, together with the
Executorrefactor and the adoption ofwhich-rs, the fork bomb issue is ultimately eliminated. At the same time, removingcmd.exe /Calso resolves a series of other issues caused by its usage.Fixes
cmd.exe /Cwrapper on Windows could be fixednode -e ...volta-cli/volta#1791Fun thing
Footnotes
https://github.com/rust-lang/rustup/blob/318c5b7072de9e33d4608213aae7cecdc99e178b/src/env_var.rs#L8 ↩