hash: convert hashing context to a structure

The `git_hash_context` is a union containing the different hash-specific states for SHA1, its unsafe variant as well as SHA256. We know that only one of these states will ever be in use at the same time because hash contexts cannot be used for multiple different hashes at the same point in time. We're about to extend the structure though to keep track of the hash algorithm used to initialize the context, which is impossible to do while the context is a union. Refactor it to instead be a structure that contains the union of context states. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jan 31, 2025 at 13:55 UTC 52eef501e17078b369da571d7e6b72c7494bb779
2 files changed +22 -21
hash.h
+7 -6
@@ -234,13 +234,14 @@ enum get_oid_result {
234 #endif
235
236 /* A suitably aligned type for stack allocations of hash contexts. */
237 -union git_hash_ctx {
238 - git_SHA_CTX sha1;
239 - git_SHA_CTX_unsafe sha1_unsafe;
240 -
241 - git_SHA256_CTX sha256;
237 +struct git_hash_ctx {
238 + union {
239 + git_SHA_CTX sha1;
240 + git_SHA_CTX_unsafe sha1_unsafe;
241 + git_SHA256_CTX sha256;
242 + } state;
243 };
243 -typedef union git_hash_ctx git_hash_ctx;
244 +typedef struct git_hash_ctx git_hash_ctx;
245
246 typedef void (*git_hash_init_fn)(git_hash_ctx *ctx);
247 typedef void (*git_hash_clone_fn)(git_hash_ctx *dst, const git_hash_ctx *src);
object-file.c
+15 -15
@@ -88,82 +88,82 @@ static const struct object_id null_oid_sha256 = {
88
89 static void git_hash_sha1_init(git_hash_ctx *ctx)
90 {
91 - git_SHA1_Init(&ctx->sha1);
91 + git_SHA1_Init(&ctx->state.sha1);
92 }
93
94 static void git_hash_sha1_clone(git_hash_ctx *dst, const git_hash_ctx *src)
95 {
96 - git_SHA1_Clone(&dst->sha1, &src->sha1);
96 + git_SHA1_Clone(&dst->state.sha1, &src->state.sha1);
97 }
98
99 static void git_hash_sha1_update(git_hash_ctx *ctx, const void *data, size_t len)
100 {
101 - git_SHA1_Update(&ctx->sha1, data, len);
101 + git_SHA1_Update(&ctx->state.sha1, data, len);
102 }
103
104 static void git_hash_sha1_final(unsigned char *hash, git_hash_ctx *ctx)
105 {
106 - git_SHA1_Final(hash, &ctx->sha1);
106 + git_SHA1_Final(hash, &ctx->state.sha1);
107 }
108
109 static void git_hash_sha1_final_oid(struct object_id *oid, git_hash_ctx *ctx)
110 {
111 - git_SHA1_Final(oid->hash, &ctx->sha1);
111 + git_SHA1_Final(oid->hash, &ctx->state.sha1);
112 memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
113 oid->algo = GIT_HASH_SHA1;
114 }
115
116 static void git_hash_sha1_init_unsafe(git_hash_ctx *ctx)
117 {
118 - git_SHA1_Init_unsafe(&ctx->sha1_unsafe);
118 + git_SHA1_Init_unsafe(&ctx->state.sha1_unsafe);
119 }
120
121 static void git_hash_sha1_clone_unsafe(git_hash_ctx *dst, const git_hash_ctx *src)
122 {
123 - git_SHA1_Clone_unsafe(&dst->sha1_unsafe, &src->sha1_unsafe);
123 + git_SHA1_Clone_unsafe(&dst->state.sha1_unsafe, &src->state.sha1_unsafe);
124 }
125
126 static void git_hash_sha1_update_unsafe(git_hash_ctx *ctx, const void *data,
127 size_t len)
128 {
129 - git_SHA1_Update_unsafe(&ctx->sha1_unsafe, data, len);
129 + git_SHA1_Update_unsafe(&ctx->state.sha1_unsafe, data, len);
130 }
131
132 static void git_hash_sha1_final_unsafe(unsigned char *hash, git_hash_ctx *ctx)
133 {
134 - git_SHA1_Final_unsafe(hash, &ctx->sha1_unsafe);
134 + git_SHA1_Final_unsafe(hash, &ctx->state.sha1_unsafe);
135 }
136
137 static void git_hash_sha1_final_oid_unsafe(struct object_id *oid, git_hash_ctx *ctx)
138 {
139 - git_SHA1_Final_unsafe(oid->hash, &ctx->sha1_unsafe);
139 + git_SHA1_Final_unsafe(oid->hash, &ctx->state.sha1_unsafe);
140 memset(oid->hash + GIT_SHA1_RAWSZ, 0, GIT_MAX_RAWSZ - GIT_SHA1_RAWSZ);
141 oid->algo = GIT_HASH_SHA1;
142 }
143
144 static void git_hash_sha256_init(git_hash_ctx *ctx)
145 {
146 - git_SHA256_Init(&ctx->sha256);
146 + git_SHA256_Init(&ctx->state.sha256);
147 }
148
149 static void git_hash_sha256_clone(git_hash_ctx *dst, const git_hash_ctx *src)
150 {
151 - git_SHA256_Clone(&dst->sha256, &src->sha256);
151 + git_SHA256_Clone(&dst->state.sha256, &src->state.sha256);
152 }
153
154 static void git_hash_sha256_update(git_hash_ctx *ctx, const void *data, size_t len)
155 {
156 - git_SHA256_Update(&ctx->sha256, data, len);
156 + git_SHA256_Update(&ctx->state.sha256, data, len);
157 }
158
159 static void git_hash_sha256_final(unsigned char *hash, git_hash_ctx *ctx)
160 {
161 - git_SHA256_Final(hash, &ctx->sha256);
161 + git_SHA256_Final(hash, &ctx->state.sha256);
162 }
163
164 static void git_hash_sha256_final_oid(struct object_id *oid, git_hash_ctx *ctx)
165 {
166 - git_SHA256_Final(oid->hash, &ctx->sha256);
166 + git_SHA256_Final(oid->hash, &ctx->state.sha256);
167 /*
168 * This currently does nothing, so the compiler should optimize it out,
169 * but keep it in case we extend the hash size again.