Skip to content

Fix stash_foreach crash on NULL and non-UTF-8 stash messages - #1321

Open
shivampwm2020 wants to merge 1 commit into
rust-lang:mainfrom
shivampwm2020:fix-1320-stash-foreach-msg
Open

shivampwm2020 wants to merge 1 commit into
rust-lang:mainfrom
shivampwm2020:fix-1320-stash-foreach-msg

Conversation

@shivampwm2020

Copy link
Copy Markdown

Fixes #1320

Problem

Repository::stash_foreach crashes when a stash reflog entry has no message
or a message that is not valid UTF-8. The no-message case is a segfault; the
non-UTF-8 case is a panic.

Root cause

src/stash.rs:165 in the stash_cb callback:

unsafe { CStr::from_ptr(message) }.to_str().unwrap()

libgit2 documents the message parameter of git_stash_cb as optional, and
it is NULL for a reflog entry with no message, so CStr::from_ptr is called
with a null pointer (undefined behavior, observed as SIGSEGV). A message that
is not valid UTF-8 makes to_str() return Err and the unwrap() panic.

Fix

Convert the pointer with the crate's existing opt_bytes helper, which is
already the idiom for optional C strings, and map the result:

match unsafe { crate::opt_bytes(&index, message) } {
    Some(bytes) => String::from_utf8_lossy(bytes),
    None => Cow::Borrowed(""),
}
.as_ref(),

Behavior decisions:

  • NULL message: the callback now receives an empty string, which is exactly
    what the issue requests and matches the existing contract for absent
    messages elsewhere in the crate.
  • Non-UTF-8 message: String::from_utf8_lossy, i.e. invalid sequences become
    U+FFFD. This is the same approach the issue reporter used as a workaround
    (String::from_utf8_lossy over entry.message_bytes()), and it keeps the
    callback infallible, so it does not turn a crash into a new error users must
    handle.

Public API / semver

The public StashCb type is unchanged:

pub type StashCb<'a> = dyn FnMut(usize, &str, &Oid) -> bool + 'a;

&str is still passed, so there is no semver-visible change and no update
needed for existing callers.

Testing

Added stash::tests::stash_foreach_missing_and_non_utf8_message, which creates
a stash, rewrites its reflog message to be first empty and then caf\xe9, and
asserts stash_foreach yields "" and "caf\u{fffd}".

Against the unpatched callback the new test reproduces the reported crash:

$ cargo test --lib stash_foreach_missing
running 1 test
error: test failed, to rerun pass `--lib`

Caused by:
  process didn't exit successfully: `.../git2-...` (signal: 11, SIGSEGV: invalid memory reference)

With the fix:

$ cargo test --lib
running 220 tests
test result: ok. 220 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

$ cargo fmt -- --check
$ cargo clippy --all-targets --all-features
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 44s

stash_cb passed the libgit2 message pointer straight to
CStr::from_ptr(...).to_str().unwrap(). libgit2 documents the message as
possibly NULL, so this dereferenced a null pointer, and a non-UTF-8
message made the unwrap panic.

Convert the pointer with the existing opt_bytes helper, returning an
empty string for NULL, and use String::from_utf8_lossy for invalid
UTF-8. The public StashCb signature is unchanged.

Fixes rust-lang#1320
@rustbot rustbot added the S-waiting-on-review Status: Waiting on review label Oct 16, 2026

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

S-waiting-on-review Status: Waiting on review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stash_foreach crashes on stash entries with no message or a non-UTF-8 message

2 participants