]> git.ipfire.org Git - thirdparty/git.git/commitdiff
hash: make git_hash_discard() idempotent
authorJeff King <peff@peff.net>
Wed, 8 Jul 2026 03:52:57 +0000 (23:52 -0400)
committerJunio C Hamano <gitster@pobox.com>
Wed, 8 Jul 2026 04:56:00 +0000 (21:56 -0700)
You must always either finalize or discard a hash context to release any
resources, but you must call only one such function. This creates extra
work for some callers, since their cleanup code paths need to know
whether they got there via their happy path (and the finalization
happened) or due to an error (in which case they need to discard).

Let's add an "active" flag that turns a redundant discard into a noop.
That lets you safely do this:

    git_hash_init(&ctx, algo);
    ...
    if (some_error)
            goto out;
    ...
    git_hash_final(result, &ctx);

  out:
    git_hash_discard(&ctx);

This should avoid future errors, and will also let us simplify a few
existing callers (in future patches).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
hash.c
hash.h

diff --git a/hash.c b/hash.c
index 55d1d41770366a0130af92280936fa34a7ee0513..b1296f0018d0dce61b592d2674bbfda173567967 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -285,6 +285,7 @@ void git_hash_free(struct git_hash_ctx *ctx)
 void git_hash_init(struct git_hash_ctx *ctx, const struct git_hash_algo *algop)
 {
        algop->init_fn(ctx);
+       ctx->active = true;
 }
 
 void git_hash_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src)
@@ -300,16 +301,21 @@ void git_hash_update(struct git_hash_ctx *ctx, const void *in, size_t len)
 void git_hash_final(unsigned char *hash, struct git_hash_ctx *ctx)
 {
        ctx->algop->final_fn(hash, ctx);
+       ctx->active = false;
 }
 
 void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
 {
        ctx->algop->final_oid_fn(oid, ctx);
+       ctx->active = false;
 }
 
 void git_hash_discard(struct git_hash_ctx *ctx)
 {
+       if (!ctx->active)
+               return;
        ctx->algop->discard_fn(ctx);
+       ctx->active = false;
 }
 
 uint32_t hash_algo_by_name(const char *name)
diff --git a/hash.h b/hash.h
index 121ecf13aae6beb1e49f3e79486671e2b43e182f..cf94ad5700278885f485e6d2de29a716fe1e64a0 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -281,6 +281,7 @@ struct git_hash_ctx {
                git_SHA_CTX_unsafe sha1_unsafe;
                git_SHA256_CTX sha256;
        } state;
+       bool active;
 };
 
 typedef void (*git_hash_init_fn)(struct git_hash_ctx *ctx);