Skip to content

Conversation

@coolreader18
Copy link
Member

@coolreader18 coolreader18 commented Sep 1, 2025

Now much more of nix uses IO-safe types!

Summary by CodeRabbit

  • New Features

    • Safer POSIX process spawning with optional setsid support on supported platforms.
  • Bug Fixes

    • More consistent FD inheritance and blocking behavior across POSIX and subprocess paths.
    • Clearer error messages for signal non-blocking checks.
    • Reduced FD churn and improved reliability for memory-mapped files.
    • Minor fixes for IO and directory listing from file descriptors.
  • Refactor

    • Large migration from raw FD integers to safer, lifetime-aware FD handling; duplication/dup2 semantics improved.
  • Chores

    • Updated POSIX-related dependency to a newer minor version.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 1, 2025

Walkthrough

Bumps nix to 0.30, adds Owned::leak to crt_fd, and migrates many raw i32/RawFd usages to typed BorrowedFd/OwnedFd/MaybeFd across mmap, posix subprocess, posix, signal, and other unix call sites; posix_spawn is reimplemented using nix::spawn and several public signatures changed.

Changes

Cohort / File(s) Summary
Dependency bump
Cargo.toml
Update nix crate 0.29 → 0.30; no feature changes.
CRT FD API
common/src/crt_fd.rs
Add pub fn leak<'fd>(self) -> Borrowed<'fd> to convert OwnedBorrowed without closing.
mmap FD refactor
stdlib/src/mmap.rs
Replace raw RawFd/File usage with crt_fd wrappers; PyMmap.fdAtomicCell<i32>; MmapNewArgs.filenoi32; mapping and fstat use Borrowed/Owned, anonymous mappings kept for -1.
POSIX subprocess FD typing
stdlib/src/posixsubprocess.rs
Introduce typed FD abstractions (Fd, MaybeFd, BorrowedFd<'_>); make ForkExecArgs lifetime-generic and retype many fields; propagate typed FDs through fork/exec, dup/close, inheritance, and error paths.
POSIX module overhaul
vm/src/stdlib/posix.rs
Migrate APIs to BorrowedFd/OwnedFd; rename raw_set_inheritableset_inheritable(BorrowedFd); dup/dup2 now return OwnedFd with Dup2Args<'_>; reimplement posix_spawn/posix_spawnp via nix::spawn (file actions/attrs); update many callsites to pass typed FDs.
Unix callsite tweaks
vm/src/stdlib/io.rs, vm/src/stdlib/os.rs
Remove redundant .as_raw() conversions when calling nix APIs (pass fd directly).
Signal FD borrow check
vm/src/stdlib/signal.rs
Use Borrowed::try_borrow_raw(fd) for non-blocking checks; format error messages using numeric fd via as_raw().

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Py as Python caller
  participant M as mmap::py_new
  participant CRT as crt_fd (Borrowed/Owned)
  participant OS as OS (fstat/mmap)

  Py->>M: py_new(MmapNewArgs{fileno: i32, ...})
  alt fileno >= 0
    M->>CRT: Borrowed::try_borrow_raw(fileno) -> Borrowed
    CRT->>CRT: duplicate -> Owned (new_fd)
    M->>OS: fstat(Borrowed)
    M->>OS: mmap/map_* using &new_fd
    M-->>Py: PyMmap{ fd: AtomicCell(new_fd_raw) }
  else anonymous
    M->>OS: map_anon(...)
    M-->>Py: PyMmap{ fd: AtomicCell(-1) }
  end
Loading
sequenceDiagram
  autonumber
  participant Py as Python caller
  participant F as fork_exec(ForkExecArgs<'fd'>)
  participant K as KeepFds
  participant N as dup helpers / nix::spawn
  participant EP as errpipe (Fd)

  Py->>F: fork_exec(ForkExecArgs<'fd'>)
  F->>K: build keep list (&[BorrowedFd])
  F->>N: set_inheritable / dup stdio via BorrowedFd/MaybeFd
  F->>EP: prepare errpipe (Fd)
  alt child path
    F->>N: exec(&ForkExecArgs<'_'>, ProcArgs)
    N->>N: perform dup/close using BorrowedFd/OwnedFd
    N->>N: call nix::spawn with file actions/attrs
  else parent path
    F-->>Py: pid or error from EP
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • youknowone
  • arihant2math

Poem

I nibbled on FDs, soft and neat,
Borrowed or Owned—no accidental bleat.
Spawn hops safer, mmap fields glow,
Nix 0.30 helped the garden grow.
Hop, dup, leak — a rabbit's little show. 🐇✨


📜 Recent review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1b25724 and 3b60133.

📒 Files selected for processing (2)
  • stdlib/src/mmap.rs (6 hunks)
  • stdlib/src/posixsubprocess.rs (8 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.rs: Follow the default rustfmt code style (cargo fmt to format)
Always run clippy to lint code (cargo clippy) before completing tasks. Fix any warnings or lints that are introduced by your 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:

  • stdlib/src/mmap.rs
  • stdlib/src/posixsubprocess.rs
🧬 Code graph analysis (2)
stdlib/src/mmap.rs (3)
common/src/crt_fd.rs (1)
  • try_borrow_raw (260-266)
vm/src/stdlib/posix.rs (1)
  • dup (1679-1684)
common/src/fileutils.rs (2)
  • fstat (11-21)
  • fstat (98-162)
stdlib/src/posixsubprocess.rs (1)
vm/src/stdlib/posix.rs (14)
  • try_from_object (192-200)
  • try_from_object (204-212)
  • try_from_object (693-697)
  • try_from_object (1178-1180)
  • try_from_object (1184-1186)
  • try_from_object (1822-1834)
  • try_from_object (2216-2231)
  • obj (1153-1161)
  • obj (1823-1823)
  • obj (2217-2217)
  • pipe (896-902)
  • set_inheritable (6-15)
  • set_inheritable (866-868)
  • dup (1679-1684)
🔇 Additional comments (15)
stdlib/src/mmap.rs (5)

30-30: LGTM! Good use of crt_fd for safer FD handling.

The addition of the crt_fd import aligns well with the migration to typed FD abstractions.


180-180: Verify the atomic cell usage for fd field.

The change from RawFd to AtomicCell<i32> for the fd field maintains the same underlying type but adds atomic operations. This is appropriate for thread-safe access to the file descriptor value.


368-381: Good FD lifecycle management with proper duplication.

The FD duplication logic correctly:

  1. Duplicates the FD using unistd::dup to create an OwnedFd
  2. Uses the new FD reference for mmap operations
  3. Returns ownership of the FD alongside the mmap object

This ensures proper lifetime management and prevents use-after-close issues.


388-388: Proper handling of FD storage.

The use of map_or(-1, |fd| fd.into_raw()) correctly stores -1 for anonymous mappings and extracts the raw FD from the owned FD for file-backed mappings.


843-845: Clean migration to typed FD operations for fstat.

The size method now properly:

  1. Borrows the raw FD safely using try_borrow_raw
  2. Uses the typed fstat function with the borrowed FD
  3. Maintains proper error handling with IO-safe types
stdlib/src/posixsubprocess.rs (10)

21-21: LGTM! Comprehensive FD trait imports for typed FD handling.

The imports properly include all necessary traits for working with both owned and borrowed file descriptors.


35-35: Good use of lifetime parameter for borrowed FDs.

The function signature now properly accepts ForkExecArgs<'_> with a lifetime parameter, enabling safe borrowing of file descriptors throughout the fork/exec process.


61-61: Excellent lifetime parameterization of ForkExecArgs.

Adding the 'fd lifetime parameter to ForkExecArgs enables proper tracking of borrowed file descriptor lifetimes, ensuring they remain valid throughout the subprocess creation.


123-167: Well-designed FD wrapper types with proper trait implementations.

The Fd and MaybeFd types provide excellent abstractions:

  • Fd wraps a BorrowedFd<'static> for valid file descriptors
  • MaybeFd handles the -1 sentinel value case elegantly
  • All necessary traits (Write, AsRawFd, IntoRawFd, AsFd) are properly implemented
  • The conversion from OwnedFd ensures proper ownership transfer

169-193: Clean handling of optional FDs with MaybeFd enum.

The MaybeFd enum provides a type-safe way to handle the Python convention of using -1 to indicate "no file descriptor", with proper conversions and raw FD access when needed.


201-211: Proper typing of FD fields in ForkExecArgs.

All FD-related fields are now properly typed:

  • fds_to_keep uses BorrowedFd<'fd> for FDs that need to remain open
  • Standard I/O FDs use MaybeFd to handle optional pipes
  • Error pipe FDs use Fd as they're always required

297-311: Excellent refactoring of stdio duplication logic.

The dup_into_stdio helper function cleanly handles:

  • FD duplication when needed (avoiding conflicts with stdio FDs)
  • Setting inheritance flags appropriately
  • The special case where an FD is already at the target stdio position

This consolidates previously duplicated logic and makes it more maintainable.


264-266: Good use of typed posix::set_inheritable function.

The code properly uses the typed BorrowedFd parameter for set_inheritable, ensuring type safety throughout the FD inheritance setup.


377-387: Clean adaptation of KeepFds to use BorrowedFd.

The KeepFds struct now properly:

  • Stores borrowed FDs with appropriate lifetime
  • Uses BorrowedFd::as_raw_fd for binary search comparisons
  • Maintains the same lookup efficiency while adding type safety

483-490: Proper handling of FD iteration in brute force closing.

The code correctly:

  • Chains the FD ranges using typed iterators
  • Extracts raw FDs only when needed for the libc call
  • Uses unsafe appropriately for the low-level libc::close call
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
common/src/crt_fd.rs (1)

193-195: Clarify/strengthen semantics of Owned::leak to avoid misuse

This safely returns a Borrowed with an arbitrary lifetime while intentionally “leaking” the fd. Consider making the lifetime explicit and signaling the leak via 'static, plus marking it must_use, to reduce accidental misuse.

Suggested change:

-    pub fn leak<'fd>(self) -> Borrowed<'fd> {
-        unsafe { Borrowed::borrow_raw(self.into_raw()) }
-    }
+    /// Intentionally leaks the underlying file descriptor and returns a borrowed
+    /// view of it. The fd will not be closed automatically; the caller is
+    /// responsible for closing it later (e.g. via crt_fd::close on a reconstructed Owned).
+    #[must_use]
+    pub fn leak(self) -> Borrowed<'static> {
+        unsafe { Borrowed::borrow_raw(self.into_raw()) }
+    }

Alternatively, keep the generic lifetime but document the safety expectations prominently.

stdlib/src/mmap.rs (1)

180-180: Consider adding documentation for the fd field change.

The change from RawFd to AtomicCell<i32> is part of the migration to typed FD wrappers. The field now stores -1 for anonymous mappings and the raw FD value otherwise.

Consider adding a doc comment to clarify the sentinel value:

+    /// The file descriptor for this mmap. -1 for anonymous mappings.
     fd: AtomicCell<i32>,
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2b67f40 and 54e4c56.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (8)
  • Cargo.toml (1 hunks)
  • common/src/crt_fd.rs (1 hunks)
  • stdlib/src/mmap.rs (6 hunks)
  • stdlib/src/posixsubprocess.rs (8 hunks)
  • vm/src/stdlib/io.rs (1 hunks)
  • vm/src/stdlib/os.rs (1 hunks)
  • vm/src/stdlib/posix.rs (17 hunks)
  • vm/src/stdlib/signal.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 (cargo fmt to format)
Always run clippy to lint code (cargo clippy) before completing tasks. Fix any warnings or lints that are introduced by your 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:

  • vm/src/stdlib/os.rs
  • common/src/crt_fd.rs
  • vm/src/stdlib/io.rs
  • vm/src/stdlib/signal.rs
  • stdlib/src/mmap.rs
  • stdlib/src/posixsubprocess.rs
  • vm/src/stdlib/posix.rs
🧬 Code graph analysis (6)
vm/src/stdlib/os.rs (1)
vm/src/stdlib/posix.rs (1)
  • dup (1679-1684)
vm/src/stdlib/io.rs (1)
stdlib/src/fcntl.rs (1)
  • fcntl (59-90)
vm/src/stdlib/signal.rs (1)
common/src/crt_fd.rs (3)
  • try_borrow_raw (260-266)
  • as_raw (184-186)
  • as_raw (269-271)
stdlib/src/mmap.rs (3)
common/src/crt_fd.rs (1)
  • try_borrow_raw (260-266)
vm/src/stdlib/posix.rs (1)
  • dup (1679-1684)
common/src/fileutils.rs (2)
  • fstat (11-21)
  • fstat (98-162)
stdlib/src/posixsubprocess.rs (2)
vm/src/stdlib/posix.rs (14)
  • try_from_object (192-200)
  • try_from_object (204-212)
  • try_from_object (693-697)
  • try_from_object (1178-1180)
  • try_from_object (1184-1186)
  • try_from_object (1822-1834)
  • try_from_object (2216-2231)
  • obj (1153-1161)
  • obj (1823-1823)
  • obj (2217-2217)
  • pipe (896-902)
  • set_inheritable (6-15)
  • set_inheritable (866-868)
  • dup (1679-1684)
common/src/crt_fd.rs (14)
  • as_raw_fd (74-76)
  • as_raw_fd (107-109)
  • as_raw_fd (221-223)
  • as_raw_fd (297-299)
  • into_raw_fd (78-81)
  • into_raw_fd (235-237)
  • as_fd (214-216)
  • as_fd (290-292)
  • from (200-202)
  • from (207-209)
  • from (276-278)
  • from (283-285)
  • borrow_raw (100-105)
  • borrow_raw (247-250)
vm/src/stdlib/posix.rs (1)
vm/src/stdlib/nt.rs (1)
  • set_inheritable (93-100)
⏰ 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: Check the WASM package and demo
  • GitHub Check: Run snippets and cpython tests on wasm-wasi
  • GitHub Check: Check Rust code with rustfmt and clippy
  • GitHub Check: Run rust tests (windows-latest)
  • GitHub Check: Run rust tests (ubuntu-latest)
  • GitHub Check: Run rust tests (macos-latest)
  • GitHub Check: Run snippets and cpython tests (windows-latest)
  • GitHub Check: Run snippets and cpython tests (macos-latest)
  • GitHub Check: Ensure compilation on various targets
  • GitHub Check: Run snippets and cpython tests (ubuntu-latest)
🔇 Additional comments (41)
Cargo.toml (1)

187-187: nix 0.30 bump looks good; feature set still valid

The enabled features (fs, user, process, term, time, signal, ioctl, socket, sched, zerocopy, dir, hostname, net, poll) match nix’s current feature list. The API change toward I/O-safe FDs (AsFd/BorrowedFd) also aligns with 0.30.

Refs: nix 0.30 features and modules; fcntl now generic over AsFd. (docs.rs, github.com)

vm/src/stdlib/io.rs (1)

3975-3976: Pass AsFd to nix::fcntl::fcntl — correct for 0.30’s I/O-safe API

Using Fildes (implements AsFd) directly matches nix 0.30’s signature for fcntl.

Refs: fcntl now generic over AsFd. (github.com)

vm/src/stdlib/signal.rs (1)

273-282: Typed-FD nonblocking check is correct and clearer

Borrowing via crt_fd::Borrowed::try_borrow_raw and calling nix::fcntl with the typed fd matches nix 0.30’s API; the error message now prints the raw fd explicitly, which is helpful.

Refs: nix 0.30 fcntl AsFd; features include signal/fcntl. (github.com, docs.rs)

vm/src/stdlib/os.rs (1)

381-381: LGTM!

The removal of fno.as_raw() when calling nix::unistd::dup is correct. According to the nix 0.30 changelog and the broader migration to IO-safe types, dup now accepts BorrowedFd directly instead of raw file descriptors.

stdlib/src/mmap.rs (6)

30-30: LGTM!

The addition of rustpython_common::crt_fd import is appropriate for the migration from raw file descriptors to typed FD wrappers.


341-342: LGTM!

The conversion to typed FD handling using crt_fd::Borrowed::try_borrow_raw is correct. This properly converts the raw FD to a borrowed FD wrapper, returning None for the sentinel value -1 (anonymous mappings).


368-381: LGTM!

The refactored FD handling correctly:

  1. Duplicates the FD using unistd::dup to get an OwnedFd
  2. Maps the memory using the new FD via typed references
  3. Returns the owned FD for lifecycle management
  4. Falls back to anonymous mapping when no FD is provided

388-388: LGTM!

The FD storage correctly uses map_or(-1, |fd| fd.into_raw()) to store the sentinel value -1 for anonymous mappings or the raw FD value otherwise.


843-844: LGTM!

The size method correctly retrieves the FD using try_borrow_raw and uses fstat to get the file size, consistent with the new typed FD approach.


343-344: fstat import verified
The use nix::sys::stat::fstat; statement exists on line 27, so fstat(fd) is properly imported and available.

stdlib/src/posixsubprocess.rs (11)

21-21: LGTM!

The import of FD-related types from std::os::fd is appropriate for the migration to typed file descriptors.


35-35: LGTM!

The function signature correctly uses the lifetime parameter 'fd for the ForkExecArgs to ensure proper FD borrowing.


61-61: LGTM!

The struct correctly includes a lifetime parameter 'fd to track the lifetime of borrowed file descriptors.


123-167: LGTM!

The new Fd and MaybeFd types provide proper abstraction for FD handling:

  • Fd wraps a BorrowedFd<'static> for valid FDs
  • MaybeFd handles the sentinel value -1 case
  • Proper trait implementations for AsRawFd, IntoRawFd, AsFd, and Write

201-211: LGTM!

The field types have been correctly updated to use the new FD wrappers:

  • fds_to_keep now uses BorrowedFd<'fd> for proper lifetime tracking
  • All pipe FDs use MaybeFd to handle the -1 sentinel case
  • Error pipe FDs use Fd as they must be valid

230-238: LGTM!

The exec function correctly:

  1. Takes a reference to ForkExecArgs to avoid moving
  2. Uses the error pipe FD directly without creating a File
  3. Properly writes error information to the pipe

264-266: LGTM!

The code correctly uses posix::set_inheritable with the borrowed FD and compares raw FD values for the error pipe check.


297-311: LGTM!

The dup_into_stdio helper function is well-designed:

  • Properly handles the MaybeFd enum
  • Sets inheritance for FDs that are already at the target
  • Uses the provided closure for duplication when needed

377-387: LGTM!

The KeepFds struct and should_keep method correctly:

  • Use BorrowedFd with proper lifetime tracking
  • Convert to raw FD only for comparison in binary search
  • Properly check if an FD should be kept based on the criteria

483-490: LGTM!

The brute force FD closing correctly:

  • Chains the FDs to keep with proper raw FD extraction
  • Uses tuple_windows to generate ranges between kept FDs
  • Safely closes FDs using libc::close

276-283: Potential issue with FD duplication in stdin case.

When c2pwrite is FD 0 (stdin), the code duplicates it and sets it as inheritable. However, there's a potential issue: if dup fails, the function returns early without proper cleanup.

Consider handling the error case more gracefully:

     let c2pwrite = match args.c2pwrite {
         MaybeFd::Some(c2pwrite) if c2pwrite.as_raw_fd() == 0 => {
-            let fd = unistd::dup(c2pwrite)?;
-            posix::set_inheritable(fd.as_fd(), true)?;
-            MaybeFd::Some(fd.into())
+            match unistd::dup(c2pwrite) {
+                Ok(fd) => {
+                    posix::set_inheritable(fd.as_fd(), true)?;
+                    MaybeFd::Some(fd.into())
+                }
+                Err(e) => return Err(e),
+            }
         }
         fd => fd,
     };

Likely an incorrect or invalid review comment.

vm/src/stdlib/posix.rs (20)

4-4: Adopt io-safe FDs in imports — LGTM.


6-15: Helper for inheritable flag is correct and side-effect free.
Uses F_GETFD/F_SETFD with FD_CLOEXEC as expected; no redundant syscalls when flags unchanged.


46-47: Importing OwnedFd/BorrowedFd/AsFd aligns the module with nix 0.30 IO-safety.


386-388: fchdir now accepts BorrowedFd — good parity with nix’s signature.


437-440: fchown[at]/fchown conversions are correct with DirFd::get() and BorrowedFd.


857-863: get_inheritable logic is correct.
Checks FD_CLOEXEC bit directly; result maps to Python bool properly.


866-868: Wrapper delegates to the shared helper — nice reuse.


871-877: get_blocking correctly inspects O_NONBLOCK.


880-893: set_blocking toggles O_NONBLOCK correctly and avoids redundant F_SETFL.


896-902: pipe sets non-inheritable on both ends — matches PEP 446 expectations.


942-946: _fchmod takes BorrowedFd and uses nix::sys::stat::fchmod — good migration.


983-985: fchmod wrapper is correct passthrough to _fchmod.


1223-1228: openpty makes both ends non-inheritable — good catch.


1424-1461: posix_spawn: file_actions mapping looks right.

  • Open: uses OFlag::from_bits_retain and Mode::from_bits_retain (acceptable given platform variance).
  • Close/Dup2: straightforward mapping to nix’s file actions.
    Error mapping to IOErrorBuilder with filename context is a nice touch.

1464-1467: posix_spawn: attributes and flags wiring is sound.

  • setsigdef/setsigmask: builds SigSet then sets flags.
  • setpgroup/resetids: correct flags.
  • setsid: good cfg-gated support with a clear NotImplemented on unsupported targets.

Also applies to: 1478-1482, 1485-1489, 1492-1493, 1496-1511, 1524-1528, 1538-1540


1552-1559: posix_spawn/p: result conversion and error mapping — LGTM.


1679-1684: dup returns OwnedFd and enforces non-inheritability — correct per PEP 446.


1687-1694: Dup2Args ownership model is sensible for nix 0.30’s dup2 API.
BorrowedFd for source and OwnedFd for target enables safe in-place replacement.


1697-1705: Align dup2 return value with CPython or document deviation. CPython’s os.dup2 returns None; here you return the new file descriptor. Either change this to return None to match CPython or explicitly note the intentional change in your docs/CHANGELOG.


373-375: Confirm that DirFd::get() yields a raw file descriptor (RawFd) as required by nix::unistd::symlinkat, not a wrapper type.

}

#[derive(Copy, Clone)]
enum MaybeFd {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be more correct to have:

type MaybeFd = Option<(FD type)>

or maybe even a newtype:

struct MaybeFd<T>(Option<T>)

?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, None corresponds to -1, not PyNone

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, I see. Then this is probably the best I can think about atm

Copy link
Member

@youknowone youknowone Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Some/None naming the best? It looks a bit confusing.

If it needs option-like operations, #[derive(result_like::OptionLike)] will be helpful.

Then this code also work

if let Some(value) = maybe_fd.into_option() {
    ...
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I've renamed the variants, which I think makes it more clear.

Copy link
Member

@youknowone youknowone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good. please check the comment before merge

@youknowone youknowone merged commit 0c8ae3a into RustPython:main Sep 3, 2025
12 checks passed
@coolreader18 coolreader18 deleted the upd-nix branch September 4, 2025 04:21
@coderabbitai coderabbitai bot mentioned this pull request Oct 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants