more hostenv isolation#7886
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (6)
💤 Files with no reviewable changes (1)
📝 WalkthroughWalkthroughIntroduces centralized libc/Win32 return-value helpers, converts many host_env wrappers to use these helpers, modernizes wide-string APIs to ChangesUnified refactor (single cohesive cohort)
Estimated code review effort 🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
|
e96a933 to
9788fcf
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/vm/src/stdlib/_winapi.rs (1)
233-254:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse WTF-8 conversion for CreateProcess arguments to support surrogate paths.
The current
wcstringclosure usesWideCString::from_str(s.expect_str()), which narrows to UTF-8-only strings. This is inconsistent with the rest of the file, which usesas_wtf8().to_wide_cstring()to preserve WTF-8 representations (including surrogates) for Windows paths. Theexpect_str()call will panic on valid Windows inputs containing unpaired surrogates that RustPython can represent.Use
as_wtf8().to_wide_cstring()directly, and remove the.transpose()?error handling since this method returnsWideCStringdirectly rather than aResult.Proposed fix
- let wcstring = |s: PyStrRef| { - widestring::WideCString::from_str(s.expect_str()).map_err(|err| err.to_pyexception(vm)) - }; + let wcstring = |s: PyStrRef| s.as_wtf8().to_wide_cstring(); @@ - let app_name = args.name.map(wcstring).transpose()?; - let current_dir = args.current_dir.map(wcstring).transpose()?; + let app_name = args.name.map(wcstring); + let current_dir = args.current_dir.map(wcstring); let mut command_line = args .command_line - .map(|s| wcstring(s).map(|w| w.into_vec_with_nul())) - .transpose()?; + .map(|s| wcstring(s).into_vec_with_nul());🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_winapi.rs` around lines 233 - 254, The wcstring closure currently uses WideCString::from_str(s.expect_str()), which rejects WTF-8 surrogate data; replace it by calling s.as_wtf8().to_wide_cstring() so CreateProcess args preserve surrogate paths, and update the call sites (where app_name = args.name.map(wcstring).transpose()? , current_dir = args.current_dir.map(wcstring).transpose()? and command_line mapping) to account for to_wide_cstring() returning WideCString directly (remove the unnecessary .transpose()? / Result-handling and adjust the command_line mapping to convert the WideCString into a NUL-terminated Vec using into_vec_with_nul()) so no panics occur for unpaired surrogates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/host_env/src/winapi.rs`:
- Around line 190-215: create_process_w_raw currently forwards command_line and
env slices straight to CreateProcessW which can read past the slice if they are
not properly UTF-16 NUL-terminated; add input validation in
create_process_w_raw: if command_line.is_some() ensure the slice is non-empty
and its last u16 == 0 (single NUL terminator) and return an
Err(io::Error::new(..., "unterminated command_line")) if not; for env.is_some()
ensure the slice is either at least two u16 long and the last two u16 values are
0 (double NUL terminator) and return Err(...) if not (alternatively treat an
empty env slice as invalid or require callers to pass None); perform these
checks before calling CreateProcessW so the API contract is enforced for any
internal caller of create_process_w_raw.
In `@crates/stdlib/src/overlapped.rs`:
- Around line 1254-1258: The code currently uses
widestring::WideCString::from_str_truncate when constructing name_wide for
create_event_w, which silently truncates on embedded NULs; change this to the
fallible WideCString::from_str and propagate its error as a Python ValueError
via the same ToPyException conversion pattern used in _winapi.rs so callers see
the invalid-name error instead of silently opening a wrong kernel object; update
the code paths around name_wide (the variable and its use in
host_winapi::create_event_w) to return/convert the WideCString::from_str error
into a ToPyException ValueError before calling create_event_w, keeping the
existing set_from_windows_err mapping for host_winapi errors.
---
Outside diff comments:
In `@crates/vm/src/stdlib/_winapi.rs`:
- Around line 233-254: The wcstring closure currently uses
WideCString::from_str(s.expect_str()), which rejects WTF-8 surrogate data;
replace it by calling s.as_wtf8().to_wide_cstring() so CreateProcess args
preserve surrogate paths, and update the call sites (where app_name =
args.name.map(wcstring).transpose()? , current_dir =
args.current_dir.map(wcstring).transpose()? and command_line mapping) to account
for to_wide_cstring() returning WideCString directly (remove the unnecessary
.transpose()? / Result-handling and adjust the command_line mapping to convert
the WideCString into a NUL-terminated Vec using into_vec_with_nul()) so no
panics occur for unpaired surrogates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 129f362b-0538-4aea-89ee-e7696c96b622
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (31)
crates/host_env/src/fcntl.rscrates/host_env/src/io_unsupported.rscrates/host_env/src/mmap.rscrates/host_env/src/msvcrt.rscrates/host_env/src/multiprocessing.rscrates/host_env/src/nt.rscrates/host_env/src/os.rscrates/host_env/src/overlapped.rscrates/host_env/src/posix_wasi.rscrates/host_env/src/resource.rscrates/host_env/src/shm.rscrates/host_env/src/signal.rscrates/host_env/src/socket.rscrates/host_env/src/testconsole.rscrates/host_env/src/winapi.rscrates/host_env/src/windows.rscrates/host_env/src/winreg.rscrates/host_env/src/wmi.rscrates/stdlib/src/fcntl.rscrates/stdlib/src/multiprocessing.rscrates/stdlib/src/overlapped.rscrates/stdlib/src/socket.rscrates/vm/Cargo.tomlcrates/vm/src/exceptions.rscrates/vm/src/stdlib/_io.rscrates/vm/src/stdlib/_winapi.rscrates/vm/src/stdlib/_wmi.rscrates/vm/src/stdlib/nt.rscrates/vm/src/stdlib/posix.rscrates/vm/src/stdlib/time.rscrates/vm/src/stdlib/winreg.rs
💤 Files with no reviewable changes (1)
- crates/vm/Cargo.toml
…VALID_FILE_ATTRIBUTES patterns
Remove unused IntoPyException impl for rustix::io::Errno and the rustix entry in crates/vm/Cargo.toml. rustix is now only depended on by host_env.
- winapi.rs: pass None to create_event_w; the recent Option<&WideCStr> migration left one call site still passing a raw null pointer. - exceptions.rs: gate ToPyException for LockfError with cfg(any(unix, target_os = "wasi")), matching host_env::fcntl's own cfg. The previous cfg let it compile on wasm32-unknown-unknown where host_env::fcntl does not exist. - io_unsupported.rs: derive Eq on FileMode alongside PartialEq to satisfy clippy::derive_partial_eq_without_eq.
- exceptions.rs: gate ToPyException for LockfError with cfg(all(unix, not(target_os = "redox"))) to match the type's own cfg in host_env/src/fcntl.rs (LockfError is not built on wasi). - signal.rs: CheckLibcResult is only used in unix-gated functions; split import so it is not pulled in for windows. - mmap.rs: remove CheckWin32Handle from imports; no longer used after switching to HandleToOwned-based RAII. - overlapped.rs: remove INVALID_HANDLE_VALUE from connect_pipe import; the call now uses .check_valid().
- signal.rs: reorder cfg-gated imports per rustfmt. - socket.rs: gate ToPyException import to cfg(all(unix, not(target_os = "redox"))); it is only used inside sendmsg which has the same gate, so it was unused on windows.
Add host_env wrappers and replace the corresponding vm call sites: - host_env::errno::strerror_string for libc::strerror - host_env::io::write_stderr_raw for libc::write(STDERR_FILENO,...) - host_env::locale::localeconv_data reused from vm::format - host_env::os::abort for the inline abort extern - host_env::os::urandom wraps getrandom; getrandom moves from vm to host_env - host_env::posix::lchmod for the macOS/BSD lchmod extern - host_env::posix::fcopyfile for the macOS fcopyfile extern - host_env::nt::wputenv for the Windows _wputenv extern vm/format.rs's get_locale_info now uses host_env on both unix and windows instead of the unix-only libc::localeconv path.
- host_env::time::tz: wraps the libc tzset/timezone/daylight/tzname globals on non-msvc, non-wasm32 targets. vm::stdlib::time now reads these via the typed wrappers instead of declaring its own externs. - host_env::winsound (windows): exposes PlaySoundW (via a typed PlaySoundSource enum), Beep, and MessageBeep. vm::stdlib::winsound drops its inline FFI block and routes through host_env.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
crates/vm/src/stdlib/_winapi.rs (1)
233-254:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAlign CreateProcess string conversion with the rest of the Windows API surface.
The
wcstringclosure at line 234 usesWideCString::from_str(s.expect_str()), but the rest of this refactor standardized Win32 inputs toas_wtf8().to_wide_cstring()to handle Pythonstrvalues with lone surrogates. This makes CreateProcess the inconsistent outlier forname,command_line, andcurrent_dir, andexpect_str()can panic on inputs the other Windows APIs now accept safely.Since null byte validation is already performed in lines 237–249, the closure can be simplified to directly call
to_wide_cstring()without the error-mapping wrapper:Suggested fix
- let wcstring = |s: PyStrRef| { - widestring::WideCString::from_str(s.expect_str()).map_err(|err| err.to_pyexception(vm)) - }; + let wcstring = |s: PyStrRef| s.as_wtf8().to_wide_cstring();Then apply the pattern to all three usages:
- let app_name = args.name.map(wcstring).transpose()?; - let current_dir = args.current_dir.map(wcstring).transpose()?; + let app_name = args.name.map(wcstring); + let current_dir = args.current_dir.map(wcstring); let mut command_line = args .command_line - .map(|s| wcstring(s).map(|w| w.into_vec_with_nul())) - .transpose()?; + .map(|s| wcstring(s).into_vec_with_nul());🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/_winapi.rs` around lines 233 - 254, The CreateProcess conversion uses WideCString::from_str with s.expect_str(), which is inconsistent with other Win32 APIs and can panic on lone surrogates; change the wcstring closure to call s.as_wtf8().to_wide_cstring() (dropping expect_str and the manual map_err wrapper) and then apply that wcstring to args.name, args.command_line, and args.current_dir usages (the existing null-byte checks remain). Ensure you keep the same transpose/? flow for app_name, current_dir, and command_line so error handling is preserved.crates/vm/src/stdlib/winsound.rs (1)
159-169:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject negative beep durations before casting to
u32.Lines 165-168 cast
args.durationdirectly tou32. A call likewinsound.Beep(440, -1)turns into4_294_967_295ms instead of failing fast.Suggested fix
if !(37..=32767).contains(&args.frequency) { return Err(vm.new_value_error("frequency must be in 37 thru 32767")); } + if args.duration < 0 { + return Err(vm.new_value_error("duration must be non-negative")); + } if rustpython_host_env::winsound::beep(args.frequency as u32, args.duration as u32) { Ok(()) } else { Err(vm.new_runtime_error("Failed to beep"))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/winsound.rs` around lines 159 - 169, The Beep wrapper currently casts args.duration to u32 without rejecting negatives, allowing values like -1 to wrap to large u32; update the Beep function to validate args.duration is non-negative (and optionally within a sensible max) before casting, returning vm.new_value_error on negative durations; locate the check near the existing frequency validation in Beep (using BeepArgs and VirtualMachine) and perform the duration check prior to calling rustpython_host_env::winsound::beep(args.frequency as u32, args.duration as u32).crates/vm/src/stdlib/nt.rs (1)
1068-1075:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winKeep
filenameon non-Ioreadlinkfailures.Line 1075 converts the remaining
ReadlinkErrorvariants straight into a Python exception, but those variants no longer have access topath. That dropsOSError.filename/message context for path-specific failures that are not plainio::Errors. Please keep explicit path-aware mapping here instead of the catch-all conversion.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/stdlib/nt.rs` around lines 1068 - 1075, The non-Io ReadlinkError variants in fn readlink currently call err.to_pyexception(vm) which loses the original path context; update the match arm for Err(err) (from host_nt::readlink / host_nt::ReadlinkError) to map each non-Io variant into an OSError that retains the filename by using OSErrorBuilder::with_filename(&err, path.clone(), vm) (or the appropriate constructor that accepts the error and path) instead of calling to_pyexception directly, so that OSError.filename and the message include the original path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/vm/src/exceptions.rs`:
- Around line 1507-1513: In the ToPyException impl for
rustpython_host_env::nt::ReadlinkError, change the NotSymbolicLink arm to return
an OSError instead of a ValueError: replace the call to vm.new_value_error("not
a symbolic link") with vm.new_os_error("not a symbolic link") so that
ReadlinkError::NotSymbolicLink maps to an OSError-family exception (keep the
existing error message text).
In `@crates/vm/src/stdlib/winreg.rs`:
- Around line 258-270: The error path currently returns a generic OSError string
for host_winreg::connect_registry failures; replace that with the Win32-backed
exception helper by calling the existing os_error_from_windows_code function
with the registry error code and vm so the Python-visible exception contains the
proper Win32 error code and message (i.e., in the branch where res != 0, return
Err(os_error_from_windows_code(res, vm)) instead of
vm.new_os_error(format!(...))). Ensure you reference
host_winreg::connect_registry, the res variable, and PyHkey::new when making the
change.
---
Outside diff comments:
In `@crates/vm/src/stdlib/_winapi.rs`:
- Around line 233-254: The CreateProcess conversion uses WideCString::from_str
with s.expect_str(), which is inconsistent with other Win32 APIs and can panic
on lone surrogates; change the wcstring closure to call
s.as_wtf8().to_wide_cstring() (dropping expect_str and the manual map_err
wrapper) and then apply that wcstring to args.name, args.command_line, and
args.current_dir usages (the existing null-byte checks remain). Ensure you keep
the same transpose/? flow for app_name, current_dir, and command_line so error
handling is preserved.
In `@crates/vm/src/stdlib/nt.rs`:
- Around line 1068-1075: The non-Io ReadlinkError variants in fn readlink
currently call err.to_pyexception(vm) which loses the original path context;
update the match arm for Err(err) (from host_nt::readlink /
host_nt::ReadlinkError) to map each non-Io variant into an OSError that retains
the filename by using OSErrorBuilder::with_filename(&err, path.clone(), vm) (or
the appropriate constructor that accepts the error and path) instead of calling
to_pyexception directly, so that OSError.filename and the message include the
original path.
In `@crates/vm/src/stdlib/winsound.rs`:
- Around line 159-169: The Beep wrapper currently casts args.duration to u32
without rejecting negatives, allowing values like -1 to wrap to large u32;
update the Beep function to validate args.duration is non-negative (and
optionally within a sensible max) before casting, returning vm.new_value_error
on negative durations; locate the check near the existing frequency validation
in Beep (using BeepArgs and VirtualMachine) and perform the duration check prior
to calling rustpython_host_env::winsound::beep(args.frequency as u32,
args.duration as u32).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: d7bacdfe-cfe5-47b1-9a04-ff3bf7040d5e
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (42)
crates/host_env/Cargo.tomlcrates/host_env/src/errno.rscrates/host_env/src/fcntl.rscrates/host_env/src/io.rscrates/host_env/src/io_unsupported.rscrates/host_env/src/lib.rscrates/host_env/src/mmap.rscrates/host_env/src/msvcrt.rscrates/host_env/src/multiprocessing.rscrates/host_env/src/nt.rscrates/host_env/src/os.rscrates/host_env/src/overlapped.rscrates/host_env/src/posix.rscrates/host_env/src/posix_wasi.rscrates/host_env/src/resource.rscrates/host_env/src/shm.rscrates/host_env/src/signal.rscrates/host_env/src/socket.rscrates/host_env/src/testconsole.rscrates/host_env/src/time.rscrates/host_env/src/winapi.rscrates/host_env/src/windows.rscrates/host_env/src/winreg.rscrates/host_env/src/winsound.rscrates/host_env/src/wmi.rscrates/stdlib/src/fcntl.rscrates/stdlib/src/multiprocessing.rscrates/stdlib/src/overlapped.rscrates/stdlib/src/socket.rscrates/vm/Cargo.tomlcrates/vm/src/exceptions.rscrates/vm/src/format.rscrates/vm/src/stdlib/_io.rscrates/vm/src/stdlib/_winapi.rscrates/vm/src/stdlib/_wmi.rscrates/vm/src/stdlib/nt.rscrates/vm/src/stdlib/os.rscrates/vm/src/stdlib/posix.rscrates/vm/src/stdlib/time.rscrates/vm/src/stdlib/winreg.rscrates/vm/src/stdlib/winsound.rscrates/vm/src/vm/mod.rs
✅ Files skipped from review due to trivial changes (1)
- crates/host_env/src/io_unsupported.rs
- vm::stdlib::os::unsetenv had a second _wputenv call site that still referenced the removed inline extern. Route it through host_env::nt::wputenv like putenv. - rustfmt fixups in exceptions.rs (boolean chain layout) and the two winsound files.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/host_env/src/winsound.rs (1)
19-20: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winReject
SND_MEMORY | SND_ASYNCcombination in the safe wrapper.When
SND_MEMORYis combined withSND_ASYNCon Win32PlaySoundW, the caller must keep the sound buffer valid until playback completes. The currentplay_sound()accepts arbitrary flags, allowing another caller to combine these flags and return while WinMM still holds a pointer into borrowed Rust memory. Add validation to reject this unsafe combination.♻️ Proposed fix
+const SND_ASYNC: u32 = 0x0001; + /// Returns `Ok(())` when `PlaySoundW` returns non-zero, an error otherwise. pub fn play_sound(source: PlaySoundSource<'_>, flags: u32) -> Result<(), PlaySoundError> { + if matches!(source, PlaySoundSource::Memory(_)) && flags & SND_ASYNC != 0 { + return Err(PlaySoundError); + } + let ptr: *const u16 = match source { PlaySoundSource::Stop => core::ptr::null(), PlaySoundSource::Memory(buf) => buf.as_ptr().cast(), PlaySoundSource::Name(s) => s.as_ptr(), };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/host_env/src/winsound.rs` around lines 19 - 20, The safe wrapper must prevent the unsafe combination SND_MEMORY | SND_ASYNC because PlaySoundW requires the buffer to outlive async playback; update the play_sound() path that handles the Memory(&'a [u8]) variant to detect when flags include both SND_MEMORY and SND_ASYNC and return an Err (or other safe error) instead of calling into WinMM, rejecting the call; reference the Memory enum variant and the play_sound() function to locate the check and ensure the validation runs before any FFI call so no borrowed buffer is handed to PlaySoundW when async is requested.
♻️ Duplicate comments (1)
crates/vm/src/exceptions.rs (1)
1509-1514:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMap
NotSymbolicLinktoOSError.Line 1513 still returns
ValueError, but the non-symlinkreadlinkfailure path should stay in theOSErrorfamily so callers can handle it consistently.In CPython, what exception type does `os.readlink()` raise when the target path is not a symbolic link?💡 Proposed fix
impl ToPyException for rustpython_host_env::nt::ReadlinkError { fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef { match self { Self::Io(err) => err.to_pyexception(vm), - Self::NotSymbolicLink => vm.new_value_error("not a symbolic link"), + Self::NotSymbolicLink => vm.new_os_error("not a symbolic link"), Self::InvalidReparseData => vm.new_os_error("Invalid reparse data"), } } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/vm/src/exceptions.rs` around lines 1509 - 1514, The ToPyException impl for rustpython_host_env::nt::ReadlinkError maps the NotSymbolicLink variant to a ValueError; change that mapping so NotSymbolicLink returns an OSError instead (use vm.new_os_error with an appropriate message like "not a symbolic link") in the impl for rustpython_host_env::nt::ReadlinkError so callers of readlink remain in the OSError family.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@crates/host_env/src/winsound.rs`:
- Around line 19-20: The safe wrapper must prevent the unsafe combination
SND_MEMORY | SND_ASYNC because PlaySoundW requires the buffer to outlive async
playback; update the play_sound() path that handles the Memory(&'a [u8]) variant
to detect when flags include both SND_MEMORY and SND_ASYNC and return an Err (or
other safe error) instead of calling into WinMM, rejecting the call; reference
the Memory enum variant and the play_sound() function to locate the check and
ensure the validation runs before any FFI call so no borrowed buffer is handed
to PlaySoundW when async is requested.
---
Duplicate comments:
In `@crates/vm/src/exceptions.rs`:
- Around line 1509-1514: The ToPyException impl for
rustpython_host_env::nt::ReadlinkError maps the NotSymbolicLink variant to a
ValueError; change that mapping so NotSymbolicLink returns an OSError instead
(use vm.new_os_error with an appropriate message like "not a symbolic link") in
the impl for rustpython_host_env::nt::ReadlinkError so callers of readlink
remain in the OSError family.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 2c77d80f-66ad-46eb-b7e8-6aaae57605d2
📒 Files selected for processing (4)
crates/host_env/src/winsound.rscrates/vm/src/exceptions.rscrates/vm/src/stdlib/os.rscrates/vm/src/stdlib/winsound.rs
- host_env::winapi::create_process: assert that the command_line buffer is NUL-terminated and that the env block ends with a double-NUL, matching the Win32 CreateProcessW contract. - stdlib::overlapped CreateEvent: replace WideCString::from_str_truncate with the fallible from_str(), so embedded NULs in the event name surface as ValueError instead of being silently truncated. - vm::exceptions::ReadlinkError::NotSymbolicLink now maps to OSError (matches Win32 ERROR_NOT_A_REPARSE_POINT semantics) rather than ValueError. - winreg::ConnectRegistry: route the non-zero return through the existing os_error_from_windows_code helper so the resulting exception carries the real winerror/message instead of a generic OSError.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
crates/host_env/src/winapi.rs (1)
221-239:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReturn
InvalidInputhere instead of panicking.Lines 221-239 and Lines 255-260 turn malformed
command_line/envbuffers intoassert!panics, even thoughcreate_process()returnsio::Result. Please make these validators fallible and propagateio::ErrorKind::InvalidInputso bad inputs stay recoverable at the API boundary.Suggested fix
#[inline] -fn assert_command_line_terminated(buf: &[u16]) { - assert!( - buf.last() == Some(&0), - "command_line buffer passed to create_process must be NUL-terminated", - ); +fn validate_command_line_terminated(buf: &[u16]) -> io::Result<()> { + if buf.last() == Some(&0) { + Ok(()) + } else { + Err(io::Error::new( + io::ErrorKind::InvalidInput, + "command_line buffer passed to create_process must be NUL-terminated", + )) + } } #[inline] -fn assert_environment_block_terminated(buf: &[u16]) { - assert!( - buf.len() >= 2 && buf[buf.len() - 2..] == [0, 0], - "env block passed to create_process must end with a double NUL terminator", - ); +fn validate_environment_block_terminated(buf: &[u16]) -> io::Result<()> { + if buf.len() >= 2 && buf[buf.len() - 2..] == [0, 0] { + Ok(()) + } else { + Err(io::Error::new( + io::ErrorKind::InvalidInput, + "env block passed to create_process must end with a double NUL terminator", + )) + } } @@ if let Some(cmd) = command_line.as_deref() { - assert_command_line_terminated(cmd); + validate_command_line_terminated(cmd)?; } if let Some(env_block) = env { - assert_environment_block_terminated(env_block); + validate_environment_block_terminated(env_block)?; }As per coding guidelines, Follow Rust best practices for error handling and memory management.
Also applies to: 255-260
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/host_env/src/winapi.rs` around lines 221 - 239, Replace the panicking validators assert_command_line_terminated and assert_environment_block_terminated with fallible versions that return io::Result<()> (or an appropriate Result type) and on invalid input return Err(io::Error::new(io::ErrorKind::InvalidInput, "<descriptive message>")) instead of assert!. Update all call sites (e.g., where create_process constructs/validates command_line and env buffers and the code paths indicated near the other validator at lines 255-260) to propagate the Result (using ? or map_err) so malformed buffers produce a recoverable InvalidInput io::Error rather than panicking.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@crates/host_env/src/winapi.rs`:
- Around line 221-239: Replace the panicking validators
assert_command_line_terminated and assert_environment_block_terminated with
fallible versions that return io::Result<()> (or an appropriate Result type) and
on invalid input return Err(io::Error::new(io::ErrorKind::InvalidInput,
"<descriptive message>")) instead of assert!. Update all call sites (e.g., where
create_process constructs/validates command_line and env buffers and the code
paths indicated near the other validator at lines 255-260) to propagate the
Result (using ? or map_err) so malformed buffers produce a recoverable
InvalidInput io::Error rather than panicking.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: b0db8cb2-3907-4994-aca4-6cbac65d9354
📒 Files selected for processing (4)
crates/host_env/src/winapi.rscrates/stdlib/src/overlapped.rscrates/vm/src/exceptions.rscrates/vm/src/stdlib/winreg.rs
CI failures: - rustfmt cleanup in exceptions.rs after the ReadlinkError change. - vm/stdlib/os.rs: drop unused ToWideString import that the wputenv migration left behind. - vm/stdlib/winsound.rs: replace explicit `&*buf` with `&buf` to satisfy clippy::explicit_auto_deref. - Lib/test/test_format.py, Lib/test/test_types.py: drop the now-stale expectedFailureIfWindows decorators on the locale-format tests; the Windows path now reads real `localeconv` data via host_env so these tests pass. Review follow-ups: - host_env::winapi::create_process: switch the new buffer terminator checks from `assert!` to fallible validators returning `io::ErrorKind::InvalidInput`, so bad inputs stay recoverable at the API boundary. - host_env::winsound::play_sound: reject `Memory(_)` together with `SND_ASYNC` (lifetime-unsafe) and `SND_MEMORY` without a `Memory(_)` source. Expand `PlaySoundError` into a variant enum. - vm::stdlib::_winapi::CreateProcess: route the Win32 path/argv strings through `as_wtf8().to_wide_cstring()` like the rest of the Windows API surface; `expect_str()` could panic on Python strings containing lone surrogates.
📦 Library DependenciesThe following Lib/ modules were modified. Here are their dependencies: [x] test: cpython/Lib/test/test_format.py (TODO: 6) dependencies: dependent tests: (no tests depend on format) [x] lib: cpython/Lib/types.py dependencies:
dependent tests: (55 tests)
Legend:
|
Summary by CodeRabbit
New Features
Refactor
API