Skip to content

Add regression test for CString::clone_into unwind safety#158807

Open
Vastargazing wants to merge 1 commit into
rust-lang:mainfrom
Vastargazing:tests/cstr-clone-into-alloc-error
Open

Add regression test for CString::clone_into unwind safety#158807
Vastargazing wants to merge 1 commit into
rust-lang:mainfrom
Vastargazing:tests/cstr-clone-into-alloc-error

Conversation

@Vastargazing

@Vastargazing Vastargazing commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Regression test for the panic-safety fix in #155707

#70201 gave <CStr as ToOwned>::clone_into a path that moved the target CString's buffer out (leaving it empty) before growing a Vec; if that growth's allocation failed and unwound, the target was left without its nul terminator, which is UB. #155707 fixed this but didn't add a test.

The failing allocator here is only honored under Miri - in a normal build a #[global_allocator] in a library test doesn't intercept the reallocation inside CString::clone_into (it lives in libstd, linked -C prefer-dynamic). So the test passes as a regular test and does the real check under Miri, with the unwind assertion gated on cfg!(miri); it runs under Miri in CI via the library-tests-under-Miri job.

This started as rust-lang/miri#5157, but per @RalfJung a std regression test belongs with the standard library.

r? @RalfJung

CString::clone_into reuses the target's allocation by moving the buffer into a Vec and growing it. If that growth's allocation fails and the alloc error hook unwinds, the target has to be left as a valid CString, but nothing covered that path.

Add a test in library/alloctests that fails the reallocation under a panicking alloc error hook and checks the target stays valid. The failing allocator is only honored under Miri - a global allocator in a library test doesn't intercept libstd's allocation in a normal build - so the unwind assertion is gated on cfg!(miri); the test still runs and passes as a regular test.
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 5, 2026
@rustbot

rustbot commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

RalfJung is not on the review rotation at the moment.
They may take a while to respond.

@RalfJung

RalfJung commented Jul 5, 2026

Copy link
Copy Markdown
Member

LGTM, thanks :)

@bors r+ rollup

@rust-bors

rust-bors Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 735cc3d has been approved by RalfJung

It is now in the queue for this repository.

🌲 The tree is currently closed for pull requests below priority 2. This pull request will be tested once the tree is reopened.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 5, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Jul 5, 2026
…-alloc-error, r=RalfJung

Add regression test for CString::clone_into unwind safety

Regression test for the panic-safety fix in rust-lang#155707

rust-lang#70201 gave `<CStr as ToOwned>::clone_into` a path that moved the target `CString`'s buffer out (leaving it empty) before growing a `Vec`; if that growth's allocation failed and unwound, the target was left without its nul terminator, which is UB. rust-lang#155707 fixed this but didn't add a test.

The failing allocator here is only honored under Miri - in a normal build a `#[global_allocator]` in a library test doesn't intercept the reallocation inside `CString::clone_into` (it lives in libstd, linked `-C prefer-dynamic`). So the test passes as a regular test and does the real check under Miri, with the unwind assertion gated on `cfg!(miri)`; it runs under Miri in CI via the library-tests-under-Miri job.

This started as rust-lang/miri#5157, but per @RalfJung a std regression test belongs with the standard library.

r? @RalfJung
jhpratt added a commit to jhpratt/rust that referenced this pull request Jul 6, 2026
…-alloc-error, r=RalfJung

Add regression test for CString::clone_into unwind safety

Regression test for the panic-safety fix in rust-lang#155707

rust-lang#70201 gave `<CStr as ToOwned>::clone_into` a path that moved the target `CString`'s buffer out (leaving it empty) before growing a `Vec`; if that growth's allocation failed and unwound, the target was left without its nul terminator, which is UB. rust-lang#155707 fixed this but didn't add a test.

The failing allocator here is only honored under Miri - in a normal build a `#[global_allocator]` in a library test doesn't intercept the reallocation inside `CString::clone_into` (it lives in libstd, linked `-C prefer-dynamic`). So the test passes as a regular test and does the real check under Miri, with the unwind assertion gated on `cfg!(miri)`; it runs under Miri in CI via the library-tests-under-Miri job.

This started as rust-lang/miri#5157, but per @RalfJung a std regression test belongs with the standard library.

r? @RalfJung
rust-bors Bot pushed a commit that referenced this pull request Jul 6, 2026
Rollup of 20 pull requests

Successful merges:

 - #158377 (add `-Zforce-intrinsic-fallback` flag)
 - #158642 (Clarify some interning details)
 - #158743 (Look for cdb location in the registry first)
 - #158775 (bootstrap: only encode RUSTFLAGS when a flag contains a space)
 - #158782 (Add and use cfg(target_has_threads) to enforce no_thread impl usage)
 - #158785 (hook intrinsic-test into aarch64-gnu)
 - #157734 (Stabilize `local_key_cell_update`)
 - #158183 (std: allocate less memory in `current_exe` for OpenBSD)
 - #158671 (Move tests batch 17)
 - #158730 (Update `FIXME(static_mut_refs)` comments)
 - #158752 (Reorganize `tests/ui/issues` [18/N])
 - #158755 (Use `ThinVec` more in the AST)
 - #158757 (Fix incorrect tracking issue for `read_le`/`read_be`)
 - #158765 (Fix ICE on non-ident path in `doc(auto_cfg values)`)
 - #158771 (library: expand HashSet::extract_if coverage)
 - #158772 (rustc-dev-guide subtree update)
 - #158776 (fix: emit diagnostic for AVR target without target-cpu)
 - #158786 (Add regression test for builtin attr macro values)
 - #158807 (Add regression test for CString::clone_into unwind safety)
 - #158825 (Fix typo)
@jhpratt

jhpratt commented Jul 6, 2026

Copy link
Copy Markdown
Member

Look like you've got some UB in the test.

@bors r- #158837 (comment)

@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jul 6, 2026
@rust-bors

rust-bors Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This pull request was unapproved.

View changes since this unapproval

@Vastargazing

Copy link
Copy Markdown
Contributor Author

Thanks. The UB is in libtest's own teardown, not the test body: with a #[global_allocator] installed, libtest frees its internal allocations (the mpmc results channel) through it, and on Windows System::dealloc reads the allocation header just before the pointer, which trips Stacked Borrows since the freed Box's provenance doesn't cover the header. It fires even with 0 tests run - it's inherent to wrapping System in a global allocator under Miri on Windows, independent of the test itself.

Two ways to resolve it, whichever you'd prefer:

  • keep it here and only install the global allocator + run the test when not all(miri, target_os = "windows") - Miri's default allocator on Windows, Linux Miri still runs it and catches the bug; or
  • move it back to a Miri ui-test (fn main, no libtest harness) - this is what Add regression test for CString::clone_into unwind safety miri#5157 was, which passed the full Miri matrix including Windows.

Happy to do either - which do you prefer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants