* Do not call `import socket` on each send()/recv() when using rustls
Use method references cached during socket creation.
* Implement reading of at most one TLS record from socket
Previous algorithm didn't take into account that recv() may return less
data than requested even for blocking sockets.
* Remove special handling of rustls "buffer full" errors
First of all, existing code does not really work and this leads to an
infinite loop: https://github.com/RustPython/RustPython/issues/7891
Second, this should never happen when rustls used properly (wrt
wants_read() and wants_write()) and thus all such errors are
implementation bugs that must be properly fixed.
* Replace own TlsConnection with rustls::Connection
* Fix waiting on a socket
1) Ensure that socket_wait() called from TLS glue code allows threads
2) Ensure that socket_wait() called from TLS glue code properly handles
EINTR on *nix
3) Ensure that select() or poll() error conditions are checked
4) Use poll() on *nix so socket descriptor values are not limited
* Remove dead code from rustls glue
* Do not present rustls errors as OSError(0, "Success")
* Remove infinite loop "detection" from rustls glue
TLS handshake cannot be infinite. Any infinite loop here is a serious
bug in implementation and should be fixed properly.
This code triggers in some cases (very short reads) with misleading
`ssl_error.SSLWantReadError: The operation did not complete (read)`.
* Add test for 1-byte max recv in TLS client
* Add regression test for https://github.com/RustPython/RustPython/issues/7891
* Fix constants in rustls glue code
* Deduplicate verify flags / record-size constants
* Larger "max encrypted TLS record length"
* Convert host_env Windows path/argv params from raw *const u16 to &WideCStr
* Migrate remaining winapi raw u16 pointer signatures to typed references
* Migrate winreg pub unsafe fn string parameters to typed references
* Add ToPyException impls for host_env error types (PyPy wrap_oserror analog)
* Add CheckLibcResult helper and apply to socket/fcntl/shm/posix_wasi
* Add Win32 BOOL/HANDLE check helpers; apply check helpers across host_env
* Apply Win32/libc check helpers to overlapped/testconsole/os.rs
* Apply Win32 check helpers to winapi.rs (partial)
* Apply Win32 check helpers across more winapi.rs functions
* Apply Win32 check helpers to nt.rs (partial)
* Add CheckWin32Sentinel helper; apply to nt.rs INVALID_HANDLE_VALUE/INVALID_FILE_ATTRIBUTES patterns
* Add OwnedHandle / HandleToOwned helper; apply to mmap create_named_mapping leak path
* Use OwnedHandle RAII in nt::pipe to eliminate manual cleanup on error path
* Use OwnedHandle in nt::chmod_follow; hoist HandleToOwned import
* Drop rustix dependency from vm crate
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.
* Fix CI failures: cross-platform regressions
- 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.
* Fix CI failures: cfg gates and unused imports
- 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().
* Fix CI failures: rustfmt and windows unused import
- 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.
* Push remaining libc/extern callsites from vm into host_env
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.
* Move time tz state and winsound FFI into host_env
- 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.
* Migrate unsetenv to host_env::nt::wputenv; rustfmt
- 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.
* Address PR review comments
- 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.
* Fix CI failures and address review follow-ups
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.
RustPython used an ancient, unmaintained version of the `dirs` crate.
This pulled in `winapi-rs` on Windows, which is an old crate that has
been deprecated in favor of `windows-rs`. `windows-rs` is maintained by
Microsoft. Bumping `dirs` to the latest version removes more `winapi-rs`
from Cargo.lock.
As for `uname`, `rustix` handles it safely so the additional crate isn't
needed.
The `page_size` crate is a simple libc wrapper for Unix and uses
`winapi-rs` for Windows. `windows-sys` and `windows-rs` are the modern
alternatives for the unmaintained `winapi-rs`. Both crates are
maintained by Microsoft - they're official. Getting the page size is a
simple call for both Unix and Windows.
Besides Unix and Windows, I also added the page size for wasm32 which
the `page_size` crate did not support. `wasm32`'s page size is a
constant that is defined by the spec, so I hard coded it without adding
additional dependencies.
Finally, I dropped `maplit` which is seven years old and only used in
one place. Calling `collect()` with a single item iterator is idiomatic
as well as better in this case because Rust can optimize it. `maplit`
called `HashMap::insert` which over allocates to amortize future allocs.