[PATCH 3/4] object, commit, tag: use size_t when parsing object buffers
- From
Elia Pinto <gitter.spiros@gmail.com>
- Date
- Oct 31, 2026, 11:09 UTC
- Message-ID
- <745c6d04d33dd118a1c8185d0b851d79d171ab98.1793444420.git.gitter.spiros@gmail.com>
- In-Reply-To
- <cover.1793444420.git.gitter.spiros@gmail.com>
Functions like parse_object_buffer(), parse_commit_buffer(), parse_tag_buffer(), and decode_tree_entry_raw() take the buffer size as an "unsigned long", while callers pass a size_t. On platforms where "long" is 32 bits, this truncates the size for objects of 4GiB or more.
When parsing large objects on those platforms, only a prefix of the buffer is parsed. For example, a signature placed at the end of a large tag can be missed.
Use size_t for the size parameter across these parsing functions. For set_commit_buffer(), the commit cache slab still stores "unsigned long" sizes due to accessors like repo_get_commit_buffer() handing out the size through an "unsigned long *" output parameter. Therefore, set_commit_buffer() narrows the size with cast_size_t_to_ulong(), dying on objects of 4GiB or more on 32-bit long platforms instead of caching a truncated size, mirroring the behavior already implemented in repo_get_commit_buffer().
parse_tree_buffer() is changed separately.
Triggering this requires processing 4GiB or more of input on a platform where "long" is 32 bits, so no test is added.
Signed-off-by: Elia Pinto <gitter.spiros@gmail.com> --- commit.c | 8 ++++---- commit.h | 6 +++--- object-file-convert.c | 2 +- object.c | 2 +- object.h | 2 +- tag.c | 2 +- tag.h | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/commit.c b/commit.c index ad26f0b40a..a94acf4e6f 100644 --- a/commit.c +++ b/commit.c @@ -366,12 +366,12 @@ void free_commit_buffer_slab(struct buffer_slab *bs) free(bs); } -void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size) +void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, size_t size) { struct commit_buffer *v = buffer_slab_at( r->parsed_objects->buffer_slab, commit); v->buffer = buffer; - v->size = size; + v->size = cast_size_t_to_ulong(size); } const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep) @@ -513,7 +513,7 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep) return ret; } -int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph) +int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph) { const char *tail = buffer; const char *bufptr = buffer; @@ -1195,7 +1195,7 @@ int parse_signed_commit(const struct commit *commit, } int parse_buffer_signed_by_header(const char *buffer, - unsigned long size, + size_t size, struct strbuf *payload, struct strbuf *signature, const struct git_hash_algo *algop) diff --git a/commit.h b/commit.h index 1061ed791b..6a6ff25e12 100644 --- a/commit.h +++ b/commit.h @@ -92,7 +92,7 @@ struct commit *lookup_commit_reference_by_name_gently(const char *name, */ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name); -int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph); +int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph); int repo_parse_commit_internal(struct repository *r, struct commit *item, int quiet_on_missing, int use_commit_graph); int repo_parse_commit_gently(struct repository *r, @@ -131,7 +131,7 @@ void free_commit_buffer_slab(struct buffer_slab *bs); * Associate an object buffer with the commit. The ownership of the * memory is handed over to the commit, and must be free()-able. */ -void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size); +void set_commit_buffer(struct repository *r, struct commit *, void *buffer, size_t size); /* * Get any cached object buffer associated with the commit. Returns NULL @@ -381,7 +381,7 @@ int run_commit_hook(int editor_is_used, const char *index_file, /* Parse the signature out of a header. */ int parse_buffer_signed_by_header(const char *buffer, - unsigned long size, + size_t size, struct strbuf *payload, struct strbuf *signature, const struct git_hash_algo *algop); diff --git a/object-file-convert.c b/object-file-convert.c index 63ee18630b..ead88c1021 100644 --- a/object-file-convert.c +++ b/object-file-convert.c @@ -51,7 +51,7 @@ int repo_oid_to_algop(struct repository *repo, const struct object_id *srcoid, static int decode_tree_entry_raw(struct object_id *oid, const char **path, size_t *len, const struct git_hash_algo *algo, - const char *buf, unsigned long size) + const char *buf, size_t size) { uint16_t mode; const unsigned hashsz = algo->rawsz; diff --git a/object.c b/object.c index 97f7fc0e87..541ac90dc6 100644 --- a/object.c +++ b/object.c @@ -258,7 +258,7 @@ enum peel_status peel_object(struct repository *r, return peel_object_ext(r, name, oid, flags, &dummy); } -struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p) +struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p) { struct object *obj; *eaten_p = 0; diff --git a/object.h b/object.h index 46cade33fb..9bf23321a7 100644 --- a/object.h +++ b/object.h @@ -241,7 +241,7 @@ struct object *parse_object_or_die(struct repository *repo, const struct object_ * parsing it. eaten_p indicates if the object has a borrowed copy * of buffer and the caller should not free() it. */ -struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p); +struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p); /* * Allocate and return an object struct, even if you do not know the type of diff --git a/tag.c b/tag.c index 1a00ded6eb..414681c64f 100644 --- a/tag.c +++ b/tag.c @@ -127,7 +127,7 @@ void release_tag_memory(struct tag *t) t->date = 0; } -int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size) +int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size) { struct object_id oid; char type[20]; diff --git a/tag.h b/tag.h index 534687c4ca..a5f0f06c82 100644 --- a/tag.h +++ b/tag.h @@ -12,7 +12,7 @@ struct tag { timestamp_t date; }; struct tag *lookup_tag(struct repository *r, const struct object_id *oid); -int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size); +int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size); int parse_tag(struct repository *r, struct tag *item); void release_tag_memory(struct tag *t); struct object *deref_tag(struct repository *r, struct object *, const char *, int);
-- 2.53.0