diff --git a/builtin/fast-import.c b/builtin/fast-import.c index aa656c5195..f6473dcc8e 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -1216,6 +1216,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark) out: free(in_buf); free(out_buf); + hashfile_checkpoint_release(&checkpoint); } /* All calls must be guarded by find_object() or find_mark() to diff --git a/builtin/patch-id.c b/builtin/patch-id.c index 2781598ede..57d9bd4a65 100644 --- a/builtin/patch-id.c +++ b/builtin/patch-id.c @@ -173,6 +173,7 @@ static size_t get_one_patchid(struct object_id *next_oid, struct object_id *resu oidclr(next_oid, the_repository->hash_algo); flush_one_hunk(result, &ctx); + git_hash_discard(&ctx); return patchlen; } diff --git a/csum-file.c b/csum-file.c index d7a682c2b6..b166f89624 100644 --- a/csum-file.c +++ b/csum-file.c @@ -55,13 +55,19 @@ void hashflush(struct hashfile *f) } } -void free_hashfile(struct hashfile *f) +static void free_hashfile_memory(struct hashfile *f) { free(f->buffer); free(f->check_buffer); free(f); } +void free_hashfile(struct hashfile *f) +{ + git_hash_discard(&f->ctx); + free_hashfile_memory(f); +} + int finalize_hashfile(struct hashfile *f, unsigned char *result, enum fsync_component component, unsigned int flags) { @@ -69,10 +75,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, hashflush(f); - if (f->skip_hash) + if (f->skip_hash) { + git_hash_discard(&f->ctx); hashclr(f->buffer, f->algop); - else + } else { git_hash_final(f->buffer, &f->ctx); + } if (result) hashcpy(result, f->buffer, f->algop); @@ -97,19 +105,10 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result, if (close(f->check_fd)) die_errno("%s: sha1 file error on close", f->name); } - free_hashfile(f); + free_hashfile_memory(f); return fd; } -void discard_hashfile(struct hashfile *f) -{ - if (0 <= f->check_fd) - close(f->check_fd); - if (0 <= f->fd) - close(f->fd); - free_hashfile(f); -} - void hashwrite(struct hashfile *f, const void *buf, uint32_t count) { while (count) { @@ -224,6 +223,11 @@ int hashfile_truncate(struct hashfile *f, struct hashfile_checkpoint *checkpoint return 0; } +void hashfile_checkpoint_release(struct hashfile_checkpoint *checkpoint) +{ + git_hash_discard(&checkpoint->ctx); +} + void crc32_begin(struct hashfile *f) { f->crc32 = crc32(0, NULL, 0); diff --git a/csum-file.h b/csum-file.h index a270738a7a..6ed74d1637 100644 --- a/csum-file.h +++ b/csum-file.h @@ -39,6 +39,7 @@ struct hashfile_checkpoint { void hashfile_checkpoint_init(struct hashfile *, struct hashfile_checkpoint *); void hashfile_checkpoint(struct hashfile *, struct hashfile_checkpoint *); int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *); +void hashfile_checkpoint_release(struct hashfile_checkpoint *); /* finalize_hashfile flags */ #define CSUM_CLOSE 1 @@ -74,7 +75,6 @@ void free_hashfile(struct hashfile *f); * Finalize the hashfile by flushing data to disk and free'ing it. */ int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int); -void discard_hashfile(struct hashfile *); void hashwrite(struct hashfile *, const void *, uint32_t); void hashflush(struct hashfile *f); void crc32_begin(struct hashfile *); diff --git a/diff.c b/diff.c index 2a9d0d8687..1568f0ed9c 100644 --- a/diff.c +++ b/diff.c @@ -6987,6 +6987,7 @@ static int diff_get_patch_id(struct diff_options *options, struct object_id *oid flush_one_hunk(oid, &ctx); } + git_hash_discard(&ctx); return 0; } diff --git a/hash.c b/hash.c index e925b9754e..55d1d41770 100644 --- a/hash.c +++ b/hash.c @@ -72,6 +72,11 @@ static void git_hash_sha1_final_oid(struct object_id *oid, struct git_hash_ctx * oid->algo = GIT_HASH_SHA1; } +static void git_hash_sha1_discard(struct git_hash_ctx *ctx) +{ + git_SHA1_Discard(&ctx->state.sha1); +} + static void git_hash_sha1_init_unsafe(struct git_hash_ctx *ctx) { ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA1]); @@ -102,6 +107,11 @@ static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, struct git_has oid->algo = GIT_HASH_SHA1; } +static void git_hash_sha1_discard_unsafe(struct git_hash_ctx *ctx) +{ + git_SHA1_Discard_unsafe(&ctx->state.sha1_unsafe); +} + static void git_hash_sha256_init(struct git_hash_ctx *ctx) { ctx->algop = unsafe_hash_algo(&hash_algos[GIT_HASH_SHA256]); @@ -135,6 +145,11 @@ static void git_hash_sha256_final_oid(struct object_id *oid, struct git_hash_ctx oid->algo = GIT_HASH_SHA256; } +static void git_hash_sha256_discard(struct git_hash_ctx *ctx) +{ + git_SHA256_Discard(&ctx->state.sha256); +} + static void git_hash_unknown_init(struct git_hash_ctx *ctx UNUSED) { BUG("trying to init unknown hash"); @@ -165,6 +180,11 @@ static void git_hash_unknown_final_oid(struct object_id *oid UNUSED, BUG("trying to finalize unknown hash"); } +static void git_hash_unknown_discard(struct git_hash_ctx *ctx UNUSED) +{ + BUG("trying to discard unknown hash"); +} + static const struct git_hash_algo sha1_unsafe_algo = { .name = "sha1", .format_id = GIT_SHA1_FORMAT_ID, @@ -176,6 +196,7 @@ static const struct git_hash_algo sha1_unsafe_algo = { .update_fn = git_hash_sha1_update_unsafe, .final_fn = git_hash_sha1_final_unsafe, .final_oid_fn = git_hash_sha1_final_oid_unsafe, + .discard_fn = git_hash_sha1_discard_unsafe, .empty_tree = &empty_tree_oid, .empty_blob = &empty_blob_oid, .null_oid = &null_oid_sha1, @@ -193,6 +214,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_unknown_update, .final_fn = git_hash_unknown_final, .final_oid_fn = git_hash_unknown_final_oid, + .discard_fn = git_hash_unknown_discard, .empty_tree = NULL, .empty_blob = NULL, .null_oid = NULL, @@ -208,6 +230,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_sha1_update, .final_fn = git_hash_sha1_final, .final_oid_fn = git_hash_sha1_final_oid, + .discard_fn = git_hash_sha1_discard, .unsafe = &sha1_unsafe_algo, .empty_tree = &empty_tree_oid, .empty_blob = &empty_blob_oid, @@ -224,6 +247,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = { .update_fn = git_hash_sha256_update, .final_fn = git_hash_sha256_final, .final_oid_fn = git_hash_sha256_final_oid, + .discard_fn = git_hash_sha256_discard, .empty_tree = &empty_tree_oid_sha256, .empty_blob = &empty_blob_oid_sha256, .null_oid = &null_oid_sha256, @@ -283,6 +307,11 @@ void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx) ctx->algop->final_oid_fn(oid, ctx); } +void git_hash_discard(struct git_hash_ctx *ctx) +{ + ctx->algop->discard_fn(ctx); +} + uint32_t hash_algo_by_name(const char *name) { if (!name) diff --git a/hash.h b/hash.h index c082a53c9a..0a23ef4dfd 100644 --- a/hash.h +++ b/hash.h @@ -37,6 +37,7 @@ # define platform_SHA1_Clone_unsafe openssl_SHA1_Clone # define platform_SHA1_Update_unsafe openssl_SHA1_Update # define platform_SHA1_Final_unsafe openssl_SHA1_Final +# define platform_SHA1_Discard_unsafe openssl_SHA1_Discard # else # define platform_SHA_CTX_unsafe SHA_CTX # define platform_SHA1_Init_unsafe SHA1_Init @@ -92,6 +93,7 @@ # define platform_SHA1_Final_unsafe platform_SHA1_Final # ifdef platform_SHA1_Clone # define platform_SHA1_Clone_unsafe platform_SHA1_Clone +# define platform_SHA1_Discard_unsafe platform_SHA1_Discard # endif # ifdef SHA1_NEEDS_CLONE_HELPER # define SHA1_NEEDS_CLONE_HELPER_UNSAFE @@ -110,9 +112,11 @@ #ifdef platform_SHA1_Clone #define git_SHA1_Clone platform_SHA1_Clone +#define git_SHA1_Discard platform_SHA1_Discard #endif #ifdef platform_SHA1_Clone_unsafe # define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe +# define git_SHA1_Discard_unsafe platform_SHA1_Discard_unsafe #endif #ifndef platform_SHA256_CTX @@ -129,6 +133,7 @@ #ifdef platform_SHA256_Clone #define git_SHA256_Clone platform_SHA256_Clone +#define git_SHA256_Discard platform_SHA256_Discard #endif #ifdef SHA1_MAX_BLOCK_SIZE @@ -142,6 +147,10 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src) { memcpy(dst, src, sizeof(*dst)); } +static inline void git_SHA1_Discard(git_SHA_CTX *ctx UNUSED) +{ + /* noop */ +} #endif #ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst, @@ -149,6 +158,10 @@ static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst, { memcpy(dst, src, sizeof(*dst)); } +static inline void git_SHA1_Discard_unsafe(git_SHA_CTX_unsafe *ctx UNUSED) +{ + /* noop */ +} #endif #ifndef SHA256_NEEDS_CLONE_HELPER @@ -156,6 +169,10 @@ static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *s { memcpy(dst, src, sizeof(*dst)); } +static inline void git_SHA256_Discard(git_SHA256_CTX *ctx UNUSED) +{ + /* noop */ +} #endif /* @@ -271,6 +288,7 @@ typedef void (*git_hash_clone_fn)(struct git_hash_ctx *dst, const struct git_has typedef void (*git_hash_update_fn)(struct git_hash_ctx *ctx, const void *in, size_t len); typedef void (*git_hash_final_fn)(unsigned char *hash, struct git_hash_ctx *ctx); typedef void (*git_hash_final_oid_fn)(struct object_id *oid, struct git_hash_ctx *ctx); +typedef void (*git_hash_discard_fn)(struct git_hash_ctx *ctx); struct git_hash_algo { /* @@ -306,6 +324,9 @@ struct git_hash_algo { /* The hash finalization function for object IDs. */ git_hash_final_oid_fn final_oid_fn; + /* Discard an initialized hash without finalizing. */ + git_hash_discard_fn discard_fn; + /* The OID of the empty tree. */ const struct object_id *empty_tree; @@ -325,6 +346,7 @@ void git_hash_clone(struct git_hash_ctx *dst, const struct git_hash_ctx *src); 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); void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx); +void git_hash_discard(struct git_hash_ctx *ctx); const struct git_hash_algo *hash_algo_ptr_by_number(uint32_t algo); struct git_hash_ctx *git_hash_alloc(void); void git_hash_free(struct git_hash_ctx *ctx); diff --git a/http.c b/http.c index b4e7b8d00b..63abbaae8a 100644 --- a/http.c +++ b/http.c @@ -2880,6 +2880,7 @@ struct http_object_request *new_http_object_request(const char *base_url, git_inflate_init(&freq->stream); the_hash_algo->init_fn(&freq->c); + freq->hash_ctx_valid = 1; freq->url = get_remote_object_url(base_url, hex, 0); @@ -2988,6 +2989,7 @@ int finish_http_object_request(struct http_object_request *freq) } git_hash_final_oid(&freq->real_oid, &freq->c); + freq->hash_ctx_valid = 0; if (freq->zret != Z_STREAM_END) { unlink_or_warn(freq->tmpfile.buf); return -1; @@ -3028,6 +3030,8 @@ void release_http_object_request(struct http_object_request **freq_p) curl_slist_free_all(freq->headers); strbuf_release(&freq->tmpfile); git_inflate_end(&freq->stream); + if (freq->hash_ctx_valid) + git_hash_discard(&freq->c); free(freq); *freq_p = NULL; diff --git a/http.h b/http.h index 729c51904d..6b0639150f 100644 --- a/http.h +++ b/http.h @@ -255,6 +255,7 @@ struct http_object_request { struct object_id oid; struct object_id real_oid; struct git_hash_ctx c; + int hash_ctx_valid; git_zstream stream; int zret; int rename; diff --git a/object-file.c b/object-file.c index 6453b1d6fa..e3c68cfb66 100644 --- a/object-file.c +++ b/object-file.c @@ -1352,6 +1352,8 @@ static int odb_transaction_files_write_object_stream(struct odb_transaction *bas state->alloc_written); state->written[state->nr_written++] = idx; } + + hashfile_checkpoint_release(&checkpoint); return 0; } @@ -1585,11 +1587,13 @@ static int check_stream_oid(git_zstream *stream, if (status != Z_STREAM_END) { error(_("corrupt loose object '%s'"), oid_to_hex(expected_oid)); + git_hash_discard(&c); return -1; } if (stream->avail_in) { error(_("garbage at end of loose object '%s'"), oid_to_hex(expected_oid)); + git_hash_discard(&c); return -1; } diff --git a/sha1/openssl.h b/sha1/openssl.h index 1038af47da..48deeb724a 100644 --- a/sha1/openssl.h +++ b/sha1/openssl.h @@ -40,12 +40,18 @@ static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst, EVP_MD_CTX_copy_ex(dst->ectx, src->ectx); } +static inline void openssl_SHA1_Discard(struct openssl_SHA1_CTX *ctx) +{ + EVP_MD_CTX_free(ctx->ectx); +} + #ifndef platform_SHA_CTX #define platform_SHA_CTX openssl_SHA1_CTX #define platform_SHA1_Init openssl_SHA1_Init #define platform_SHA1_Clone openssl_SHA1_Clone #define platform_SHA1_Update openssl_SHA1_Update #define platform_SHA1_Final openssl_SHA1_Final +#define platform_SHA1_Discard openssl_SHA1_Discard #endif #endif /* SHA1_OPENSSL_H */ diff --git a/sha256/gcrypt.h b/sha256/gcrypt.h index 17a90f1052..d91ffe73d3 100644 --- a/sha256/gcrypt.h +++ b/sha256/gcrypt.h @@ -27,13 +27,20 @@ static inline void gcrypt_SHA256_Final(unsigned char *digest, gcrypt_SHA256_CTX static inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA256_CTX *src) { + gcry_md_close(*dst); gcry_md_copy(dst, *src); } +static inline void gcrypt_SHA256_Discard(gcrypt_SHA256_CTX *ctx) +{ + gcry_md_close(*ctx); +} + #define platform_SHA256_CTX gcrypt_SHA256_CTX #define platform_SHA256_Init gcrypt_SHA256_Init #define platform_SHA256_Clone gcrypt_SHA256_Clone #define platform_SHA256_Update gcrypt_SHA256_Update #define platform_SHA256_Final gcrypt_SHA256_Final +#define platform_SHA256_Discard gcrypt_SHA256_Discard #endif diff --git a/sha256/openssl.h b/sha256/openssl.h index c1083d9491..3d457ca99d 100644 --- a/sha256/openssl.h +++ b/sha256/openssl.h @@ -40,10 +40,16 @@ static inline void openssl_SHA256_Clone(struct openssl_SHA256_CTX *dst, EVP_MD_CTX_copy_ex(dst->ectx, src->ectx); } +static inline void openssl_SHA256_Discard(struct openssl_SHA256_CTX *ctx) +{ + EVP_MD_CTX_free(ctx->ectx); +} + #define platform_SHA256_CTX openssl_SHA256_CTX #define platform_SHA256_Init openssl_SHA256_Init #define platform_SHA256_Clone openssl_SHA256_Clone #define platform_SHA256_Update openssl_SHA256_Update #define platform_SHA256_Final openssl_SHA256_Final +#define platform_SHA256_Discard openssl_SHA256_Discard #endif /* SHA256_OPENSSL_H */