From: Elia Pinto Date: Fri, 30 Oct 2026 10:28:35 GMT Subject: [PATCH 2/6] object-file: use size_t for loose object sizes Message-ID: In-Reply-To: Since c6a4629e32 (odb: use size_t for object_info.sizep and the size APIs, 2026-06-15), parse_loose_header() reports the object size as a size_t. But unpack_loose_rest() still takes an "unsigned long", which is only 32 bits on Windows. A header claiming 4GiB + 5 bytes thus makes us allocate a 6-byte buffer, the size check added by the previous commit is happy because the stream really has 5 bytes, and the caller gets that buffer back together with *oi->sizep set to 4GiB + 5. Any user of the object then reads far beyond the end of the buffer; read_loose_object() already does so when it hashes the contents. Use size_t for the size in unpack_loose_rest() and check_stream_oid(), and while at it for the size of the mapped file in map_fd(), odb_source_loose_map_object() and unpack_loose_header(), so that the whole loose object reading path agrees on the type. There is no test, as the reader allocates a buffer of the size claimed in the header before it can notice that the stream is short, so a test would need 4GiB of memory. The problem can be reproduced on Windows with the loose_obj() helper from the previous commit: printf short | loose_obj .git/objects commit $((4 * 1024 * 1024 * 1024 + 5)) followed by "git cat-file commit" on the resulting object ID. Signed-off-by: Elia Pinto --- object-file.c | 14 +++++++------- object-file.h | 6 +++--- odb/source-loose.c | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/object-file.c b/object-file.c index 6d39138511..0fc240b1e8 100644 --- a/object-file.c +++ b/object-file.c @@ -155,7 +155,7 @@ int stream_object_signature(struct repository *r, * Map and close the given loose object fd. The path argument is used for * error reporting. */ -static void *map_fd(int fd, const char *path, unsigned long *size) +static void *map_fd(int fd, const char *path, size_t *size) { void *map = NULL; struct stat st; @@ -176,9 +176,9 @@ static void *map_fd(int fd, const char *path, unsigned long *size) enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, unsigned char *map, - unsigned long mapsize, + size_t mapsize, void *buffer, - unsigned long bufsiz) + size_t bufsiz) { int status; @@ -209,7 +209,7 @@ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, } void *unpack_loose_rest(git_zstream *stream, - void *buffer, unsigned long size, + void *buffer, size_t size, const struct object_id *oid) { size_t hdrlen = strlen(buffer) + 1, bytes, n; @@ -1135,7 +1135,7 @@ int for_each_loose_file_in_source(struct odb_source *source, static int check_stream_oid(git_zstream *stream, const char *hdr, - unsigned long size, + size_t size, const char *path, const struct object_id *expected_oid, const struct git_hash_algo *algop) @@ -1143,7 +1143,7 @@ static int check_stream_oid(git_zstream *stream, struct git_hash_ctx c; struct object_id real_oid; unsigned char buf[4096]; - unsigned long total_read; + size_t total_read; int status = Z_OK; git_hash_init(&c, algop); @@ -1203,7 +1203,7 @@ int read_loose_object(struct repository *repo, int ret = -1; int fd; void *map = NULL; - unsigned long mapsize; + size_t mapsize; git_zstream stream; char hdr[MAX_HEADER_LEN]; size_t *size = oi->sizep; diff --git a/object-file.h b/object-file.h index f44758c4f8..a8da9dcd22 100644 --- a/object-file.h +++ b/object-file.h @@ -157,11 +157,11 @@ enum unpack_loose_header_result { */ enum unpack_loose_header_result unpack_loose_header(git_zstream *stream, unsigned char *map, - unsigned long mapsize, + size_t mapsize, void *buffer, - unsigned long bufsiz); + size_t bufsiz); void *unpack_loose_rest(git_zstream *stream, - void *buffer, unsigned long size, + void *buffer, size_t size, const struct object_id *oid); int parse_loose_header(const char *hdr, struct object_info *oi); diff --git a/odb/source-loose.c b/odb/source-loose.c index 50cb388c35..d77e93e7c4 100644 --- a/odb/source-loose.c +++ b/odb/source-loose.c @@ -73,7 +73,7 @@ static int read_object_info_from_path(struct odb_source_loose *loose, { int ret; int fd; - unsigned long mapsize; + size_t mapsize; void *map = NULL; git_zstream stream, *stream_to_end = NULL; char hdr[MAX_HEADER_LEN]; @@ -250,7 +250,7 @@ static int open_loose_object(struct odb_source_loose *loose, static void *odb_source_loose_map_object(struct odb_source_loose *loose, const struct object_id *oid, - unsigned long *size) + size_t *size) { const char *p; int fd = open_loose_object(loose, oid, &p); @@ -285,7 +285,7 @@ struct odb_loose_read_stream { ODB_LOOSE_READ_STREAM_ERROR, } z_state; void *mapped; - unsigned long mapsize; + size_t mapsize; char hdr[32]; int hdr_avail; int hdr_used; @@ -356,7 +356,7 @@ static int odb_source_loose_read_object_stream(struct odb_stream **out, struct odb_source_loose *loose = odb_source_loose_downcast(source); struct object_info oi = OBJECT_INFO_INIT; struct odb_loose_read_stream *st; - unsigned long mapsize; + size_t mapsize; void *mapped; mapped = odb_source_loose_map_object(loose, oid, &mapsize); -- 2.53.0