From 0a6006c5ac937d37a1e5625ecbddd31092e865b0 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Wed, 15 Jul 2026 17:54:11 -0700 Subject: [PATCH 1/2] `StashSaveOptions::pathspec()`: add regression tests for invalid path specs The test is currently marked as `#[should_panic]` because the implementation panics when the path given is invalid, a follow-up commit will switch to returning a `Result`. --- src/stash.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/stash.rs b/src/stash.rs index c1730dd9d5..bd55c38dad 100644 --- a/src/stash.rs +++ b/src/stash.rs @@ -215,7 +215,7 @@ extern "C" fn stash_apply_progress_cb( mod tests { use crate::stash::{StashApplyOptions, StashSaveOptions}; use crate::test::repo_init; - use crate::{IndexAddOption, Repository, StashFlags, Status}; + use crate::{IndexAddOption, Repository, Signature, StashFlags, Status}; use std::fs; use std::path::{Path, PathBuf}; @@ -347,4 +347,12 @@ mod tests { assert_eq!(repo.statuses(None).unwrap().len(), 1); } + + #[test] + #[should_panic] + fn test_stash_invalid_path() { + let sig = Signature::now("name", "email").unwrap(); + let mut opts = StashSaveOptions::new(sig); + opts.pathspec("abc\x00xyz"); + } } From 41ab557421dedff9e888514ff995d1c60902a094 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Wed, 15 Jul 2026 18:00:17 -0700 Subject: [PATCH 2/2] `StashSaveOptions::pathspec()`: return a `Result`, handle invalid values When the provided path spec cannot be converted to a `CString`, return an `Err` variant rather than panicking. --- src/stash.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/stash.rs b/src/stash.rs index bd55c38dad..13a81c53ca 100644 --- a/src/stash.rs +++ b/src/stash.rs @@ -1,6 +1,6 @@ use crate::build::CheckoutBuilder; use crate::util::{self, Binding}; -use crate::{panic, raw, IntoCString, Oid, Signature, StashApplyProgress, StashFlags}; +use crate::{panic, raw, Error, IntoCString, Oid, Signature, StashApplyProgress, StashFlags}; use libc::{c_char, c_int, c_void, size_t}; use std::ffi::{c_uint, CStr, CString}; use std::mem; @@ -45,11 +45,11 @@ impl<'a> StashSaveOptions<'a> { } /// Add to the array of paths patterns to build the stash. - pub fn pathspec(&mut self, pathspec: T) -> &mut Self { - let s = util::cstring_to_repo_path(pathspec).unwrap(); + pub fn pathspec(&mut self, pathspec: T) -> Result<&mut Self, Error> { + let s = util::cstring_to_repo_path(pathspec)?; self.pathspec_ptrs.push(s.as_ptr()); self.pathspec.push(s); - self + Ok(self) } /// Acquire a pointer to the underlying raw options. @@ -338,7 +338,7 @@ mod tests { assert_eq!(repo.statuses(None).unwrap().len(), 2); let mut opt = StashSaveOptions::new(signature); - opt.pathspec("file_a"); + opt.pathspec("file_a").expect("Should be a valid path spec"); repo.stash_save_ext(Some(&mut opt)).unwrap(); assert_eq!(repo.statuses(None).unwrap().len(), 0); @@ -349,10 +349,21 @@ mod tests { } #[test] - #[should_panic] fn test_stash_invalid_path() { let sig = Signature::now("name", "email").unwrap(); let mut opts = StashSaveOptions::new(sig); - opts.pathspec("abc\x00xyz"); + // Cannot use unwrap_err() because StashSaveOptions does not implement Debug + let result = match opts.pathspec("abc\x00xyz") { + Ok(_) => panic!("Expected an error"), + Err(e) => e, + }; + assert_eq!( + crate::Error::new( + crate::ErrorCode::GenericError, + crate::ErrorClass::None, + "data contained a nul byte that could not be represented as a string" + ), + result + ); } }