Skip to content

Close original standard descriptors and keep C++ streams attached - #579

Open
perfloop-agent wants to merge 2 commits into
Cpp2Rust:masterfrom
perfloop-oss:perfloop-pr-open-msy2k2kavp
Open

perfloop-agent wants to merge 2 commits into
Cpp2Rust:masterfrom
perfloop-oss:perfloop-pr-open-msy2k2kavp

Conversation

@perfloop-agent

@perfloop-agent perfloop-agent commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closing a standard descriptor in refcount output now releases the OS descriptor with that number, so open can reuse it. C++ standard streams stay attached to the original descriptor and return I/O errors after close instead of panicking or using a duplicate.

  • Borrow standard registry entries while keeping ownership of opened files, including files opened at 0–2.
  • Introduce CppStream as a mutable stream object separate from its I/O handle, leaving a home for future formatting and error state.
  • Make references, stream buffers, and copied or returned iterators refer to the same object rather than duplicate its file handle.

Generated refcount code remains safe Rust. The registry remains thread-local, with its existing ub: bad fd policy for unregistered numbers, including a first close after another thread has closed that descriptor. This is not cross-thread ownership tracking.

Floating-point formatting, padding, and sticky error flags remain unimplemented; insertion expressions still discard returned I/O errors. Application exposure and runtime performance remain unmeasured.

Testing

8 recorded checks pass with this change.

  • libcc2rs unit and doc tests
  • libcc2rs clippy
  • rules clippy
  • libcc2rs rustfmt
  • rules rustfmt
  • clang-format on changed C and C++ fixtures
  • I/O documentation Prettier
  • Scoped descriptor and C++ stream lit tests

The runtime runner passes 71 unit tests, with no failures or ignored tests, and reports no doctests. The scoped lit runner passes 44 cases, with no failures or skips.

tests/unit/fd_close_standard.c compares close/open/read and descriptor-number reuse with native C. The unsafe model's descriptor-close behavior is unchanged.

tests/unit/iostream_closed.cpp compares output after closing stdout and stderr with native C++. tests/unit/stdcopy_ostream.cpp exercises copied and returned output iterators and reads the file back. tests/unit/stdcopy_istream.cpp checks binary file-to-string reads through temporary and copied input iterators. The runtime's file_stream_io test covers binary I/O and release of the owned file while stream references remain.

The macOS unit/max.cpp/refcount generated-output check remains owned by target CI.

Case and evidence


Made by Perfloop. Human sponsor: Tomás Senart.

@perfloop
perfloop Bot force-pushed the perfloop-pr-open-msy2k2kavp branch from 3cb5fb0 to 2a70743 Compare November 1, 2026 13:40
@nunoplopes

Copy link
Copy Markdown
Contributor

@perfloop-agent The actual fix is a bit more involved. We need to create a new Stream type to hold state. For example, streams must remember the floating point formatting, string padding, etc.
We don't (shouldn't) do everything in one PR, but we need to ensure that the newly introduced type will work for all of these use cases.

Signed-off-by: Perfloop Agent <agent@perfloop.ai>
Signed-off-by: Tomás Senart <ts@perfloop.ai>
Signed-off-by: Perfloop Agent <agent@perfloop.ai>
Signed-off-by: Tomás Senart <ts@perfloop.ai>
@perfloop
perfloop Bot force-pushed the perfloop-pr-open-msy2k2kavp branch from 2a70743 to a5c0693 Compare November 2, 2026 12:53
@perfloop-agent

Copy link
Copy Markdown
Contributor Author

The stream wrapper now separates the mutable stream object from its I/O handle, so formatting and error state can live on the object. References and copied or returned iterators keep that same object instead of duplicating handles. Floating-point formatting and padding remain outside this PR.

This branch has not been deployed

No deployments
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.

2 participants