-
Notifications
You must be signed in to change notification settings - Fork 1.4k
nt.terminalsize #6374
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
nt.terminalsize #6374
Conversation
WalkthroughDefault to stdout (fd=1), derive a Windows HANDLE via Changes
Sequence DiagramsequenceDiagram
participant VM as VM code
participant crt_fd as crt_fd resolver
participant WinAPI as Windows API
participant CONOUT as CONOUT$ file
VM->>crt_fd: Borrow fd (fd.unwrap_or(1))
crt_fd-->>VM: as_handle() -> HANDLE
VM->>WinAPI: GetConsoleScreenBufferInfo(HANDLE)
alt Success
WinAPI-->>VM: CONSOLE_SCREEN_BUFFER_INFO
VM-->>VM: compute columns/lines from srWindow
else ERROR_ACCESS_DENIED
WinAPI-->>VM: ERROR_ACCESS_DENIED
VM->>CONOUT: CreateFileW("CONOUT$", GENERIC_READ|GENERIC_WRITE)
CONOUT-->>VM: temp HANDLE
VM->>WinAPI: GetConsoleScreenBufferInfo(temp HANDLE)
WinAPI-->>VM: CONSOLE_SCREEN_BUFFER_INFO
VM->>CONOUT: CloseHandle(temp HANDLE)
VM-->>VM: compute columns/lines from srWindow
else OtherError
WinAPI-->>VM: error
VM-->>VM: errno_err(vm) (propagate)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
3530295 to
6680edb
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
crates/vm/src/stdlib/nt.rs (2)
206-223: Verify handle lifetime and error semantics for standard vs non-standard fds.Two observations:
For non-standard fds (lines 214-218), the
BorrowedHandlefromcrt_fd::as_handlegoes out of scope after extracting the raw handle value. This is safe because the raw value remains valid as long as the underlying fd is open, consistent with similar patterns elsewhere in this file.For the null/invalid handle check (lines 221-223): when
GetStdHandlereturnsNULL(no associated handle), callingerrno_errmay report a stale or misleading error since no Windows error was set. Consider setting a specific error or differentiating between the two failure modes for clearer diagnostics.if h.is_null() || h == INVALID_HANDLE_VALUE { + // Note: NULL means no console attached (not an error condition per se), + // while INVALID_HANDLE_VALUE indicates a true error return Err(errno_err(vm)); }
257-261: Consider guarding against invalid window rectangles.The
srWindowcoordinates arei16(SHORT). IfRight < LeftorBottom < Top(malformed rect), the subtraction yields a negative value that wraps to a largeusize. While Windows should never return such a rect, a defensive check avoids surprising behavior in edge cases.let csbi = unsafe { csbi.assume_init() }; let w = csbi.srWindow; - let columns = (w.Right - w.Left + 1) as usize; - let lines = (w.Bottom - w.Top + 1) as usize; + let columns = (w.Right.saturating_sub(w.Left).saturating_add(1)) as usize; + let lines = (w.Bottom.saturating_sub(w.Top).saturating_add(1)) as usize; Ok(_os::TerminalSizeData { columns, lines })Alternatively, if matching CPython's exact behavior is preferred, the current implementation is acceptable.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/vm/src/stdlib/nt.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style by runningcargo fmtto format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
crates/vm/src/stdlib/nt.rs
🧬 Code graph analysis (1)
crates/vm/src/stdlib/nt.rs (3)
crates/vm/src/stdlib/winapi.rs (3)
GetStdHandle(82-96)GetLastError(172-174)std(444-444)crates/common/src/crt_fd.rs (1)
as_handle(341-345)crates/vm/src/stdlib/os.rs (2)
errno_err(39-41)std(1111-1111)
🔇 Additional comments (1)
crates/vm/src/stdlib/nt.rs (1)
235-256: CONOUT$ fallback logic is well-structured.The fallback path correctly:
- Opens
CONOUT$with appropriate access flags- Retries the screen buffer info query
- Ensures
CloseHandleis called before checking the resultThis approach matches CPython's behavior for handling redirected stdout scenarios.
6680edb to
4992e7e
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/vm/src/stdlib/nt.rs (1)
206-215: Consider removing the redundant INVALID_HANDLE_VALUE check.The
crt_fd::as_handle()function returnsio::Result<BorrowedHandle<'_>>, which means it already validates the handle internally. The explicit check forINVALID_HANDLE_VALUEon lines 213-215 is redundant becauseas_handle()would have returned an error if the handle were invalid.Apply this diff to remove the redundant check:
let fd = fd.unwrap_or(1); // default to stdout // Use _get_osfhandle for all fds let borrowed = unsafe { crt_fd::Borrowed::borrow_raw(fd) }; let handle = crt_fd::as_handle(borrowed).map_err(|e| e.to_pyexception(vm))?; let h = handle.as_raw_handle() as Foundation::HANDLE; -if h == INVALID_HANDLE_VALUE { - return Err(errno_err(vm)); -} - let mut csbi = MaybeUninit::uninit();
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/vm/src/stdlib/nt.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style by runningcargo fmtto format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
crates/vm/src/stdlib/nt.rs
🧬 Code graph analysis (1)
crates/vm/src/stdlib/nt.rs (3)
crates/common/src/crt_fd.rs (1)
as_handle(341-345)crates/vm/src/stdlib/os.rs (2)
errno_err(39-41)std(1131-1131)crates/vm/src/stdlib/winapi.rs (2)
GetLastError(172-174)std(444-444)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Check the WASM package and demo
- GitHub Check: Check Rust code with clippy
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Ensure compilation on various targets
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Run rust tests (windows-latest)
🔇 Additional comments (3)
crates/vm/src/stdlib/nt.rs (3)
217-226: LGTM! Proper error discrimination.The error handling correctly distinguishes between
ERROR_ACCESS_DENIED(which requires a fallback mechanism) and other errors (which should be propagated immediately). This matches the expected Windows console behavior where a handle might not have read permissions.
227-248: LGTM! Proper fallback implementation.The fallback correctly opens
CONOUT$(the Windows console device) whenERROR_ACCESS_DENIEDis encountered, retrieves the console buffer info, and properly closes the handle afterward. The resource management is correct, and the error propagation is appropriate.
249-253: LGTM! Correct terminal size computation.The use of
assume_init()is safe here since we only reach this point after a successfulGetConsoleScreenBufferInfocall. The window dimension calculations correctly handle inclusive bounds:(Right - Left + 1)for columns and(Bottom - Top + 1)for lines.
4992e7e to
aafa930
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/vm/src/stdlib/nt.rs (1)
238-243: Consider saving the error beforeCloseHandleto preserve the correct error code.If
GetConsoleScreenBufferInfofails and thenCloseHandlealso fails (rare but possible), the error code fromGetLastError()captured byerrno_errwould be fromCloseHandlerather than from the actual console operation.let ret = unsafe { Console::GetConsoleScreenBufferInfo(console_handle, csbi.as_mut_ptr()) }; + let err = if ret == 0 { + Some(errno_err(vm)) + } else { + None + }; unsafe { Foundation::CloseHandle(console_handle) }; - if ret == 0 { - return Err(errno_err(vm)); + if let Some(e) = err { + return Err(e); }
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
Lib/test/test_subprocess.pyis excluded by!Lib/**
📒 Files selected for processing (1)
crates/vm/src/stdlib/nt.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style by runningcargo fmtto format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
crates/vm/src/stdlib/nt.rs
🧬 Code graph analysis (1)
crates/vm/src/stdlib/nt.rs (3)
crates/common/src/crt_fd.rs (1)
as_handle(341-345)crates/vm/src/stdlib/winapi.rs (2)
GetLastError(172-174)std(444-444)crates/vm/src/stdlib/os.rs (2)
errno_err(39-41)std(1131-1131)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Run snippets and cpython tests (ubuntu-latest)
- GitHub Check: Run snippets and cpython tests (windows-latest)
- GitHub Check: Check the WASM package and demo
- GitHub Check: Run snippets and cpython tests on wasm-wasi
- GitHub Check: Check Rust code with clippy
- GitHub Check: Run snippets and cpython tests (macos-latest)
- GitHub Check: Run tests under miri
- GitHub Check: Run rust tests (macos-latest)
- GitHub Check: Run rust tests (windows-latest)
- GitHub Check: Run rust tests (ubuntu-latest)
- GitHub Check: Ensure compilation on various targets
🔇 Additional comments (2)
crates/vm/src/stdlib/nt.rs (2)
206-211: LGTM!The unified fd handling approach is clean. Defaulting to stdout (fd 1), using
crt_fd::as_handleto get the OS handle, and properly propagating errors viato_pyexceptionaligns with the existing patterns in this file.
245-249: LGTM!The terminal size computation correctly uses
srWindowbounds, and theassume_initis safely guarded by the control flow ensuringGetConsoleScreenBufferInfosucceeded. This matches CPython's approach for computing visible console dimensions.
aafa930 to
efbb6cf
Compare
efbb6cf to
9acfc46
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
crates/vm/src/stdlib/nt.rs (2)
223-240: Consider using RAII for console handle resource management.The
console_handleis manually opened and closed, which could leak the handle if a panic occurs between lines 234 and 240. While panics are unlikely in this code path, following Rust best practices would involve wrapping the handle in an RAII type with aDropimplementation.Additionally,
GetConsoleScreenBufferInfoonly requiresGENERIC_READaccess, soGENERIC_WRITEon line 227 may be unnecessary.Consider wrapping the handle:
struct ConsoleHandle(Foundation::HANDLE); impl Drop for ConsoleHandle { fn drop(&mut self) { unsafe { Foundation::CloseHandle(self.0) }; } }Then use:
- let console_handle = unsafe { + let console_handle = ConsoleHandle(unsafe { FileSystem::CreateFileW( conout.as_ptr(), - Foundation::GENERIC_READ | Foundation::GENERIC_WRITE, + Foundation::GENERIC_READ, FileSystem::FILE_SHARE_READ | FileSystem::FILE_SHARE_WRITE, std::ptr::null(), FileSystem::OPEN_EXISTING, 0, std::ptr::null_mut(), ) - }; + }); if console_handle == INVALID_HANDLE_VALUE { return Err(errno_err(vm)); } let ret = - unsafe { Console::GetConsoleScreenBufferInfo(console_handle, csbi.as_mut_ptr()) }; - unsafe { Foundation::CloseHandle(console_handle) }; + unsafe { Console::GetConsoleScreenBufferInfo(console_handle.0, csbi.as_mut_ptr()) };Based on coding guidelines, Rust best practices for resource management should be followed.
245-249: Optional: Add defensive bounds checking for window coordinates.The calculation assumes
w.Right >= w.Leftandw.Bottom >= w.Top. While the Windows API should always return valid bounds, adding defensive checks would make the code more robust against invalid data.let csbi = unsafe { csbi.assume_init() }; let w = csbi.srWindow; + if w.Right < w.Left || w.Bottom < w.Top { + return Err(vm.new_os_error("Invalid console screen buffer dimensions".to_string())); + } let columns = (w.Right - w.Left + 1) as usize; let lines = (w.Bottom - w.Top + 1) as usize;
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
crates/vm/src/stdlib/nt.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style by runningcargo fmtto format Rust code
Always run clippy to lint Rust code (cargo clippy) before completing tasks and fix any warnings or lints introduced by changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass,pymodule,pyfunction, etc.) when implementing Python functionality in Rust
Files:
crates/vm/src/stdlib/nt.rs
🧬 Code graph analysis (1)
crates/vm/src/stdlib/nt.rs (5)
crates/vm/src/stdlib/winreg.rs (1)
handle(188-190)crates/common/src/crt_fd.rs (1)
as_handle(341-345)crates/vm/src/stdlib/winapi.rs (3)
GetLastError(172-174)std(444-444)CloseHandle(77-79)crates/vm/src/stdlib/os.rs (2)
errno_err(39-41)std(1131-1131)crates/vm/src/windows.rs (3)
std(410-410)std(463-463)std(474-474)
🔇 Additional comments (1)
crates/vm/src/stdlib/nt.rs (1)
206-212: LGTM! Handle derivation approach is sound.The unified approach to derive a Windows handle from the file descriptor is well-implemented. Defaulting to stdout (fd=1) is reasonable, and the error handling properly converts I/O errors to Python exceptions.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.