-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Detect infinite recursion in uv run. #11386
Conversation
) -> anyhow::Result<ExitStatus> { | ||
// Check if max recursion depth was exceeded. This most commonly happens |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check could be pushed up higher in the call stack, but it seemed nice to have the logic for the check and the logic for setting/incrementing the counter in the same place.
c8665e1
to
170c702
Compare
// enough that it's unlikely a user actually needs this recursion depth, | ||
// but short enough that we detect recursion quickly enough to avoid OOMing | ||
// or hanging for a long time. | ||
const DEFAULT_MAX_RECURSION_DEPTH: u32 = 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At a depth of 100 this takes about 2.5 seconds to error on a relatively beefy laptop. The time to detection scales more or less linearly with this value, so I think the way to set this is basically to pick something large enough to be unlikely to cause problems, but low enough that we actually detect recursion in enough time to be useful.
The 2.5s number above is from running in debug, so if a target error time of ~2s sounds ok, then this can probably be bumped up to 500-1000 in release.
3fa9ccb
to
2dfb202
Compare
#[arg(long, hide = true, env = EnvVars::UV_RUN_MAX_RECURSION_DEPTH)] | ||
pub max_recursion_depth: Option<u32>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see a case for adding this to the CLI but... we could also just read it directly. Since you already did this, it seems okay to leave it (as a hidden option).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I made this configurable primarily to support testing (without this being configurable the test for this takes 2-3 seconds in debug), but this seemed like something that a user could theoretically want to control, and it isn't too hard to plumb this to where it needs to go.
Thanks for contributing! This looks pretty good to me. It's fine to gate the test case to Unix. |
6bf64b9
to
2d19f17
Compare
Handle potential infinite recursion if `uv run` recursively invokes `uv run`. This can happen if the shebang line of a script includes `uv run` without passing --script. Handled by adding a new environment variable, `UV_RUN_RECURSION_DEPTH`, which contains a counter of the number of times that uv run has been recursively invoked. If unset, it defaults to zero, and each time uv run starts a subprocess it increments the counter. Closes astral-sh#11220.
2d19f17
to
e4c7b90
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made some small changes. Thank you!
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.5.30` -> `0.5.31` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>astral-sh/uv (astral-sh/uv)</summary> ### [`v0.5.31`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0531) [Compare Source](astral-sh/uv@0.5.30...0.5.31) ##### Enhancements - Add `uv sync --script` ([#​11361](astral-sh/uv#11361)) - Allow PEP 508 requirements in tool requests ([#​11337](astral-sh/uv#11337)) - Allow source distributions to produce wheels with `+local` suffixes ([#​11429](astral-sh/uv#11429)) - Bring parity to `uvx` and `uv tool install` requests ([#​11345](astral-sh/uv#11345)) - Use a stable directory for local, remote, and stdin script virtual environments ([#​11347](astral-sh/uv#11347), [#​11364](astral-sh/uv#11364)) - Detect infinite recursion in `uv run` ([#​11386](astral-sh/uv#11386)) ##### Python The managed Python distributions have been updated, including: - CPython 3.14.0a5, which includes a new [tail calling interpreter](https://docs.python.org/3.14/whatsnew/3.14.html#whatsnew314-tail-call) for a significant performance improvement - The bundled OpenSSL version was updated from 3.0.15 to 3.0.16 which fixes a [security advisory](https://openssl-library.org/news/secadv/20241016.txt) See the [`python-build-standalone` release notes](https://github.com/astral-sh/python-build-standalone/releases/tag/20250212) for more details. ##### Bug fixes - Fix cross-drive script installation ([#​11167](astral-sh/uv#11167)) - Add indexes in priority order ([#​11451](astral-sh/uv#11451)) - Allow `--python <dir>` requests to match existing environments if `sys.executable` is the same file ([#​11290](astral-sh/uv#11290)) - Avoid comparing to system site packages in `--dry-run` mode ([#​11427](astral-sh/uv#11427)) - Prefer running executables in the environment with `<name>` over `<name>/__main__.py` ([#​11431](astral-sh/uv#11431)) - Retry local clones without hardlinks if they fail ([#​11421](astral-sh/uv#11421)) ##### Documentation - Update alternative-indexes.md to use `UV_INDEX` instead of `UV_EXTRA_INDEX_URL` ([#​11381](astral-sh/uv#11381)) - Update scripts guide to include using package indexes ([#​11443](astral-sh/uv#11443)) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOS4xNjYuMSIsInVwZGF0ZWRJblZlciI6IjM5LjE2Ni4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Summary
Handle potential infinite recursion if
uv run
recursively invokesuv run
. This can happen if the shebang line of a script includesuv run
, but does not pass--script
.Handled by adding a new environment variable
UV_RUN_RECURSION_DEPTH
, which contains a counter of the number of times that uv run has been recursively invoked. If unset, it defaults to zero, and each time uv run starts a subprocess we increment the counter, erroring if the value is greater than a configurable (but not currently exposed or documented) threshold.Closes #11220.
Test Plan
I've added a snapshot test to
uv/crates/uv/tests/it/run
that tests the end-to-end recursion detection flow. I've currently made it a unix-only test because I'm not sure offhand how uv run will interact with shebang lines on windows.