From 251e7af9924f9d3132a7b2f1f0f9563c829bc419 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Sun, 19 Jul 2026 01:08:41 +0000 Subject: [PATCH 1/2] hash: initialize context before cloning Our C-based clone helper requires that the context be initialized, but we neglect to do that in our Clone implementation for CryptoHasher. This does not matter when using our default block SHA-256 implementation, but it does cause a crash when using OpenSSL as the backend. Fix this by properly initializing the context before cloning into it. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- src/hash.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hash.rs b/src/hash.rs index dea2998de4..4d14e4b4fa 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -181,7 +181,10 @@ impl CryptoDigest for CryptoHasher { impl Clone for CryptoHasher { fn clone(&self) -> Self { let ctx = unsafe { c::git_hash_alloc() }; - unsafe { c::git_hash_clone(ctx, self.ctx) }; + unsafe { + c::git_hash_init(ctx, self.algo.hash_algo_ptr()); + c::git_hash_clone(ctx, self.ctx) + }; Self { algo: self.algo, ctx, From fdfcd7543e8c2c045ea215b17e6e772a9770018a Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Sun, 19 Jul 2026 01:08:42 +0000 Subject: [PATCH 2/2] rust: discard hash context when finished When we allocate a context but then abandon it, we never discard it, which means that the underlying crypto library context may leak. This doesn't happen with our default block code, but it may with OpenSSL. Note that we do call git_hash_free, which frees the memory we called from git_hash_alloc, but doesn't discard the underlying context itself. This can be seen with the following command when compiling with OpenSSL and running with nightly Rust: RUSTFLAGS='-Z sanitizer=leak' cargo test Discard the context in our context handler. Note that it is fine to do so even after finalizing the context, so our final functions which take self instead of &mut self will not mishandle memory. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- src/hash.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/hash.rs b/src/hash.rs index 4d14e4b4fa..e1f2d31fc3 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -194,7 +194,10 @@ impl Clone for CryptoHasher { impl Drop for CryptoHasher { fn drop(&mut self) { - unsafe { c::git_hash_free(self.ctx) }; + unsafe { + c::git_hash_discard(self.ctx); + c::git_hash_free(self.ctx); + }; } } @@ -356,6 +359,7 @@ pub mod c { pub fn git_hash_clone(dst: *mut c_void, src: *const c_void); pub fn git_hash_update(ctx: *mut c_void, inp: *const c_void, len: usize); pub fn git_hash_final(hash: *mut u8, ctx: *mut c_void); + pub fn git_hash_discard(ctx: *mut c_void); pub fn git_hash_final_oid(hash: *mut c_void, ctx: *mut c_void); } } @@ -450,6 +454,7 @@ mod tests { h.update(&data[2..]); let h2 = h.clone(); + let h3 = h2.clone(); let actual_oid = h.into_oid(); assert_eq!(**oid, actual_oid); @@ -463,6 +468,7 @@ mod tests { let actual_oid = h.into_oid(); assert_eq!(**oid, actual_oid); + std::mem::drop(h3); } } }