Skip to content

fix(core,assembly): replace unsound ptr::read in panic recovery#2934

Open
giwaov wants to merge 1 commit into0xMiden:nextfrom
giwaov:fix/remove-ptr-read-ub
Open

fix(core,assembly): replace unsound ptr::read in panic recovery#2934
giwaov wants to merge 1 commit into0xMiden:nextfrom
giwaov:fix/remove-ptr-read-ub

Conversation

@giwaov
Copy link
Copy Markdown
Contributor

@giwaov giwaov commented Mar 28, 2026

Description

\Program::write_to_file\ and \Library::write_to_file\ use \catch_unwind\ to convert panics from \ByteWriter\ into \io::Error. On the downcast success branch, the code uses:

\
ust
unsafe { core::ptr::read(&*err) }
\\

This is unsound: \ptr::read\ performs a bitwise copy of the \std::io::Error\ out of the \Box, but the original \Boxstd::io::Error\ is then dropped at end of scope, causing a double-drop (undefined behaviour).

Fix

Replace with *err, which safely moves the value out of the \Box\ via \DerefMove/unbox semantics no \unsafe\ needed.

Changes

  • \core/src/program/mod.rs: Replace \unsafe { core::ptr::read(&*err) }\ with *err\
  • \crates/assembly-syntax/src/library/mod.rs: Same fix

Both changes remove \unsafe\ blocks entirely from these functions.

Closes #2814

@huitseeker
Copy link
Copy Markdown
Contributor

huitseeker commented Mar 30, 2026

@amathxbt Please cease spam comments.

@github-actions
Copy link
Copy Markdown

This PR contains unsigned commits. All commits must be cryptographically signed (GPG or SSH).

Unsigned commits:

  • 2fd0051d fix(core,assembly): remove unsound ptr::read in panic recovery

For instructions on setting up commit signing and re-signing existing commits, see:
https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits

Copy link
Copy Markdown
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

This just needs a small wording change in the PR description & Changelog, otherwise LGTM.

CHANGELOG.md Outdated
- Rejected non-syscall references to exported kernel procedures in the linker ([#2902](https://github.com/0xMiden/miden-vm/issues/2902)).
#### Bug Fixes

- Removed unsound `ptr::read` in IO panic recovery that could cause a double-drop ([#2934](https://github.com/0xMiden/miden-vm/pull/2934)).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The fix here is smaller than the current wording. This patch removes UB in the downcast::<std::io::Error>() arm by replacing ptr::read with *err, but it does not make normal write failures return io::Error today. See above for details.

I think the PR title and this changelog line should say that plainly, like remove UB in panic recovery or replace unsound ptr::read in panic recovery, so readers do not think the full I/O recovery path is fixed.

Err(err) => std::panic::resume_unwind(err),
}
.map_err(|p| match p.downcast::<std::io::Error>() {
Ok(err) => *err,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The reason this still does not guarantee io::Error on normal write failure is that the writer below is not panicking with io::Error today. ByteWriter for std::io::Write uses write_all(...).expect("write failed"), so the usual panic payload is the formatted message, not std::io::Error, and this branch is skipped. I do not think that wider behavior needs to be fixed in this PR. Reworking that would mean changing how write failures are surfaced, while this patch is already valuable as the smaller safety fix: it removes the UB if the std::io::Error branch is ever reached.

Replace unsafe ptr::read with safe *err unbox in the downcast::<std::io::Error>() arm of catch_unwind panic recovery. The ptr::read performed a bitwise copy out of the Box while the Box was still dropped at end of scope, causing potential UB via double-drop. This patch removes the unsafe block entirely.

Closes 0xMiden#2814
@giwaov giwaov force-pushed the fix/remove-ptr-read-ub branch from 6e319ed to f110921 Compare March 31, 2026 10:46
@giwaov giwaov changed the title fix(core,assembly): remove unsound ptr::read in panic recovery fix(core,assembly): replace unsound ptr::read in panic recovery Mar 31, 2026
@giwaov
Copy link
Copy Markdown
Contributor Author

giwaov commented Mar 31, 2026

Updated the PR title, commit message, and CHANGELOG wording per your feedback. Now says 'replace unsound ptr::read in panic recovery' to clarify this is the smaller UB fix, not a full I/O recovery path change.

Copy link
Copy Markdown
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

Thanks! LGTM

@huitseeker huitseeker requested a review from bobbinth April 1, 2026 14:47
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.

Latent undefined behaviour in IO panic recovery (ptr::read causes double-drop)

2 participants