Skip to content

Commit 600588d

Browse files
peffgitster
authored andcommitted
hash: add platform-specific discard functions
Our git_hash_discard() is a bit hacky: it just calls git_hash_final() into a dummy result buffer, using the side effect that each implementation's Final() function will also free any resources. This is probably not too terrible, since generating the final hash is not that expensive and we'd mostly call discard on unusual or error code paths. But we can do better by widening the platform API a bit to add an explicit discard function. This requires an annoying amount of boilerplate: - Each algorithm needs a git_$ALGO_discard() wrapper that dereferences the union'd git_hash_ctx into the type-safe field. So sha1 + sha256 + sha1-unsafe, plus a BUG() for the unknown algo. And then these all need to be referenced in the git_hash_algo structs. - Platforms which don't do anything special to discard now need a fallback function which does nothing. And we need this for each algo (sha1, sha256, and sha1-unsafe). - Platforms which do need to discard must define their discard functions. This includes sha1/openssl, sha256/openssl, and sha256/gcrypt (no sha1-unsafe here as it sits atop the sha1/openssl functions). - Algo selection needs to point platform_*_Discard to the appropriate underlying macro, or indicate that the fallback should be used. We have a similar situation for the Clone function (where a straight memcpy() of the context struct is not enough for some platforms). I've tied Discard to the same flag used by Clone here, since they are basically the same problem: is the hash context a sequence of bytes, or does it need smart copying/discarding? It's easy to miss a case here since we don't even compile the implementations we aren't using. I've tested with each of: - no flags, which uses our internal sha1/sha256 implementations, both of which exercise the noop fallback function - OPENSSL_SHA1_UNSAFE=1, which checks that our unsafe macro redirections work - OPENSSL_SHA1=1, though you should not do that in real life! - OPENSSL_SHA256=1, passes tests with GIT_TEST_DEFAULT_HASH=sha256 - GCRYPT_SHA256=1, which likewise passes The other implementations do not set the CLONE_HELPER flag, so they treat the context as bytes and should be fine with the fallback. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a51b545 commit 600588d

5 files changed

Lines changed: 64 additions & 8 deletions

File tree

hash.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ static void git_hash_sha1_final_oid(struct object_id *oid, struct git_hash_ctx *
7272
oid->algo = GIT_HASH_SHA1;
7373
}
7474

75+
static void git_hash_sha1_discard(struct git_hash_ctx *ctx)
76+
{
77+
git_SHA1_Discard(&ctx->state.sha1);
78+
}
79+
7580
static void git_hash_sha1_init_unsafe(struct git_hash_ctx *ctx)
7681
{
7782
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
102107
oid->algo = GIT_HASH_SHA1;
103108
}
104109

110+
static void git_hash_sha1_discard_unsafe(struct git_hash_ctx *ctx)
111+
{
112+
git_SHA1_Discard_unsafe(&ctx->state.sha1_unsafe);
113+
}
114+
105115
static void git_hash_sha256_init(struct git_hash_ctx *ctx)
106116
{
107117
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
135145
oid->algo = GIT_HASH_SHA256;
136146
}
137147

148+
static void git_hash_sha256_discard(struct git_hash_ctx *ctx)
149+
{
150+
git_SHA256_Discard(&ctx->state.sha256);
151+
}
152+
138153
static void git_hash_unknown_init(struct git_hash_ctx *ctx UNUSED)
139154
{
140155
BUG("trying to init unknown hash");
@@ -165,6 +180,11 @@ static void git_hash_unknown_final_oid(struct object_id *oid UNUSED,
165180
BUG("trying to finalize unknown hash");
166181
}
167182

183+
static void git_hash_unknown_discard(struct git_hash_ctx *ctx UNUSED)
184+
{
185+
BUG("trying to discard unknown hash");
186+
}
187+
168188
static const struct git_hash_algo sha1_unsafe_algo = {
169189
.name = "sha1",
170190
.format_id = GIT_SHA1_FORMAT_ID,
@@ -176,6 +196,7 @@ static const struct git_hash_algo sha1_unsafe_algo = {
176196
.update_fn = git_hash_sha1_update_unsafe,
177197
.final_fn = git_hash_sha1_final_unsafe,
178198
.final_oid_fn = git_hash_sha1_final_oid_unsafe,
199+
.discard_fn = git_hash_sha1_discard_unsafe,
179200
.empty_tree = &empty_tree_oid,
180201
.empty_blob = &empty_blob_oid,
181202
.null_oid = &null_oid_sha1,
@@ -193,6 +214,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
193214
.update_fn = git_hash_unknown_update,
194215
.final_fn = git_hash_unknown_final,
195216
.final_oid_fn = git_hash_unknown_final_oid,
217+
.discard_fn = git_hash_unknown_discard,
196218
.empty_tree = NULL,
197219
.empty_blob = NULL,
198220
.null_oid = NULL,
@@ -208,6 +230,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
208230
.update_fn = git_hash_sha1_update,
209231
.final_fn = git_hash_sha1_final,
210232
.final_oid_fn = git_hash_sha1_final_oid,
233+
.discard_fn = git_hash_sha1_discard,
211234
.unsafe = &sha1_unsafe_algo,
212235
.empty_tree = &empty_tree_oid,
213236
.empty_blob = &empty_blob_oid,
@@ -224,6 +247,7 @@ const struct git_hash_algo hash_algos[GIT_HASH_NALGOS] = {
224247
.update_fn = git_hash_sha256_update,
225248
.final_fn = git_hash_sha256_final,
226249
.final_oid_fn = git_hash_sha256_final_oid,
250+
.discard_fn = git_hash_sha256_discard,
227251
.empty_tree = &empty_tree_oid_sha256,
228252
.empty_blob = &empty_blob_oid_sha256,
229253
.null_oid = &null_oid_sha256,
@@ -285,14 +309,7 @@ void git_hash_final_oid(struct object_id *oid, struct git_hash_ctx *ctx)
285309

286310
void git_hash_discard(struct git_hash_ctx *ctx)
287311
{
288-
/*
289-
* XXX Many implementations do not need to do anything here,
290-
* and a dummy final() call is wasteful. But we can't fix
291-
* that unless our implementation API exposes a discard
292-
* primitive.
293-
*/
294-
unsigned char dummy[GIT_MAX_RAWSZ];
295-
git_hash_final(dummy, ctx);
312+
ctx->algop->discard_fn(ctx);
296313
}
297314

298315
uint32_t hash_algo_by_name(const char *name)

hash.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
# define platform_SHA1_Clone_unsafe openssl_SHA1_Clone
3838
# define platform_SHA1_Update_unsafe openssl_SHA1_Update
3939
# define platform_SHA1_Final_unsafe openssl_SHA1_Final
40+
# define platform_SHA1_Discard_unsafe openssl_SHA1_Discard
4041
# else
4142
# define platform_SHA_CTX_unsafe SHA_CTX
4243
# define platform_SHA1_Init_unsafe SHA1_Init
@@ -92,6 +93,7 @@
9293
# define platform_SHA1_Final_unsafe platform_SHA1_Final
9394
# ifdef platform_SHA1_Clone
9495
# define platform_SHA1_Clone_unsafe platform_SHA1_Clone
96+
# define platform_SHA1_Discard_unsafe platform_SHA1_Discard
9597
# endif
9698
# ifdef SHA1_NEEDS_CLONE_HELPER
9799
# define SHA1_NEEDS_CLONE_HELPER_UNSAFE
@@ -110,9 +112,11 @@
110112

111113
#ifdef platform_SHA1_Clone
112114
#define git_SHA1_Clone platform_SHA1_Clone
115+
#define git_SHA1_Discard platform_SHA1_Discard
113116
#endif
114117
#ifdef platform_SHA1_Clone_unsafe
115118
# define git_SHA1_Clone_unsafe platform_SHA1_Clone_unsafe
119+
# define git_SHA1_Discard_unsafe platform_SHA1_Discard_unsafe
116120
#endif
117121

118122
#ifndef platform_SHA256_CTX
@@ -129,6 +133,7 @@
129133

130134
#ifdef platform_SHA256_Clone
131135
#define git_SHA256_Clone platform_SHA256_Clone
136+
#define git_SHA256_Discard platform_SHA256_Discard
132137
#endif
133138

134139
#ifdef SHA1_MAX_BLOCK_SIZE
@@ -142,20 +147,32 @@ static inline void git_SHA1_Clone(git_SHA_CTX *dst, const git_SHA_CTX *src)
142147
{
143148
memcpy(dst, src, sizeof(*dst));
144149
}
150+
static inline void git_SHA1_Discard(git_SHA_CTX *ctx UNUSED)
151+
{
152+
/* noop */
153+
}
145154
#endif
146155
#ifndef SHA1_NEEDS_CLONE_HELPER_UNSAFE
147156
static inline void git_SHA1_Clone_unsafe(git_SHA_CTX_unsafe *dst,
148157
const git_SHA_CTX_unsafe *src)
149158
{
150159
memcpy(dst, src, sizeof(*dst));
151160
}
161+
static inline void git_SHA1_Discard_unsafe(git_SHA_CTX_unsafe *ctx UNUSED)
162+
{
163+
/* noop */
164+
}
152165
#endif
153166

154167
#ifndef SHA256_NEEDS_CLONE_HELPER
155168
static inline void git_SHA256_Clone(git_SHA256_CTX *dst, const git_SHA256_CTX *src)
156169
{
157170
memcpy(dst, src, sizeof(*dst));
158171
}
172+
static inline void git_SHA256_Discard(git_SHA256_CTX *ctx UNUSED)
173+
{
174+
/* noop */
175+
}
159176
#endif
160177

161178
/*
@@ -271,6 +288,7 @@ typedef void (*git_hash_clone_fn)(struct git_hash_ctx *dst, const struct git_has
271288
typedef void (*git_hash_update_fn)(struct git_hash_ctx *ctx, const void *in, size_t len);
272289
typedef void (*git_hash_final_fn)(unsigned char *hash, struct git_hash_ctx *ctx);
273290
typedef void (*git_hash_final_oid_fn)(struct object_id *oid, struct git_hash_ctx *ctx);
291+
typedef void (*git_hash_discard_fn)(struct git_hash_ctx *ctx);
274292

275293
struct git_hash_algo {
276294
/*
@@ -306,6 +324,9 @@ struct git_hash_algo {
306324
/* The hash finalization function for object IDs. */
307325
git_hash_final_oid_fn final_oid_fn;
308326

327+
/* Discard an initialized hash without finalizing. */
328+
git_hash_discard_fn discard_fn;
329+
309330
/* The OID of the empty tree. */
310331
const struct object_id *empty_tree;
311332

sha1/openssl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,18 @@ static inline void openssl_SHA1_Clone(struct openssl_SHA1_CTX *dst,
4040
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
4141
}
4242

43+
static inline void openssl_SHA1_Discard(struct openssl_SHA1_CTX *ctx)
44+
{
45+
EVP_MD_CTX_free(ctx->ectx);
46+
}
47+
4348
#ifndef platform_SHA_CTX
4449
#define platform_SHA_CTX openssl_SHA1_CTX
4550
#define platform_SHA1_Init openssl_SHA1_Init
4651
#define platform_SHA1_Clone openssl_SHA1_Clone
4752
#define platform_SHA1_Update openssl_SHA1_Update
4853
#define platform_SHA1_Final openssl_SHA1_Final
54+
#define platform_SHA1_Discard openssl_SHA1_Discard
4955
#endif
5056

5157
#endif /* SHA1_OPENSSL_H */

sha256/gcrypt.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,16 @@ static inline void gcrypt_SHA256_Clone(gcrypt_SHA256_CTX *dst, const gcrypt_SHA2
3131
gcry_md_copy(dst, *src);
3232
}
3333

34+
static inline void gcrypt_SHA256_Discard(gcrypt_SHA256_CTX *ctx)
35+
{
36+
gcry_md_close(*ctx);
37+
}
38+
3439
#define platform_SHA256_CTX gcrypt_SHA256_CTX
3540
#define platform_SHA256_Init gcrypt_SHA256_Init
3641
#define platform_SHA256_Clone gcrypt_SHA256_Clone
3742
#define platform_SHA256_Update gcrypt_SHA256_Update
3843
#define platform_SHA256_Final gcrypt_SHA256_Final
44+
#define platform_SHA256_Discard gcrypt_SHA256_Discard
3945

4046
#endif

sha256/openssl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,16 @@ static inline void openssl_SHA256_Clone(struct openssl_SHA256_CTX *dst,
4040
EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);
4141
}
4242

43+
static inline void openssl_SHA256_Discard(struct openssl_SHA256_CTX *ctx)
44+
{
45+
EVP_MD_CTX_free(ctx->ectx);
46+
}
47+
4348
#define platform_SHA256_CTX openssl_SHA256_CTX
4449
#define platform_SHA256_Init openssl_SHA256_Init
4550
#define platform_SHA256_Clone openssl_SHA256_Clone
4651
#define platform_SHA256_Update openssl_SHA256_Update
4752
#define platform_SHA256_Final openssl_SHA256_Final
53+
#define platform_SHA256_Discard openssl_SHA256_Discard
4854

4955
#endif /* SHA256_OPENSSL_H */

0 commit comments

Comments
 (0)