From 783a88ba89c62af2c87c3d2eefb57fb6ce0aa4fe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 09:50:48 +0200 Subject: [PATCH 1/7] pack-objects: drop cast_size_t_to_ulong shims in get_delta() The two shims that 606c192380 (odb, packfile: use size_t for streaming object sizes, 2026-05-08) and the subsequent odb_read_object() widening introduced as scaffolding around get_delta()'s reads can now disappear: the previous commit widened diff_delta() to size_t, which was the last narrow consumer in this function. Widen size and base_size to size_t outright, drop the size_st / base_size_st bridging temporaries, and drop the two cast_size_t_to_ulong() calls. Net change is 4 lines smaller and one read-then-cast indirection gone from each odb read. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 83b0431c21..e0ae943efb 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -353,21 +353,17 @@ static void index_commit_for_bitmap(struct commit *commit) static void *get_delta(struct object_entry *entry) { - unsigned long size, base_size; - size_t delta_size; + size_t size, base_size, delta_size; void *buf, *base_buf, *delta_buf; enum object_type type; - size_t size_st = 0, base_size_st = 0; buf = odb_read_object(the_repository->objects, &entry->idx.oid, - &type, &size_st); - size = cast_size_t_to_ulong(size_st); + &type, &size); if (!buf) die(_("unable to read %s"), oid_to_hex(&entry->idx.oid)); base_buf = odb_read_object(the_repository->objects, &DELTA(entry)->idx.oid, &type, - &base_size_st); - base_size = cast_size_t_to_ulong(base_size_st); + &base_size); if (!base_buf) die("unable to read %s", oid_to_hex(&DELTA(entry)->idx.oid)); From 0ba41b5536745f848e64cfef114963b2714d65e5 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 10:49:54 +0200 Subject: [PATCH 2/7] pack-objects: drop cast_size_t_to_ulong shims in try_delta() Companion to the prior get_delta() cleanup, and the last try_delta() piece of the >4 GiB delta-path topic. Every consumer that the function's locals fed has now been widened: SIZE() / DELTA_SIZE() to size_t (prior topic), the mem_usage out-parameter and delta_cacheable() earlier in this series, and create_delta() / create_delta_index() in the immediately preceding commits. Widen the declaration of trg_size, src_size, sizediff, max_size and sz to size_t (delta_size joins them on the same line, removing the size_t delta_size line that the create_delta() widening commit added as a stop-gap), and drop the two sz_st bridge variables together with the surrounding cast_size_t_to_ulong() calls. The result is just "odb_read_object(&sz)" on both reads. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index e0ae943efb..1bf04cd5fa 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -2784,8 +2784,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, { struct object_entry *trg_entry = trg->entry; struct object_entry *src_entry = src->entry; - unsigned long trg_size, src_size, sizediff, max_size, sz; - size_t delta_size; + size_t trg_size, src_size, delta_size, sizediff, max_size, sz; unsigned ref_depth; enum object_type type; void *delta_buf; @@ -2838,12 +2837,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, /* Load data if not already done */ if (!trg->data) { - size_t sz_st = 0; packing_data_lock(&to_pack); trg->data = odb_read_object(the_repository->objects, &trg_entry->idx.oid, &type, - &sz_st); - sz = cast_size_t_to_ulong(sz_st); + &sz); packing_data_unlock(&to_pack); if (!trg->data) die(_("object %s cannot be read"), @@ -2855,12 +2852,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src, *mem_usage += sz; } if (!src->data) { - size_t sz_st = 0; packing_data_lock(&to_pack); src->data = odb_read_object(the_repository->objects, &src_entry->idx.oid, &type, - &sz_st); - sz = cast_size_t_to_ulong(sz_st); + &sz); packing_data_unlock(&to_pack); if (!src->data) { if (src_entry->preferred_base) { From 069ff038f79e5d290110d549d0091b32e76e8297 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 14:39:26 +0200 Subject: [PATCH 3/7] pack-objects: drop the last size shim in write_no_reuse_object() Continue the size_t evacuation that this series and the merged js/objects-larger-than-4gb-on-windows topic are advancing for >4 GiB objects on Windows: with the odb readers and the zlib helpers reached from do_compress() now widened end-to-end, the last cast_size_t_to_ulong() shim in this function can be removed, and do_compress() itself can carry the new size type through. Two cast_size_t_to_ulong() shims remain in this file; they feed the tree-walk API, which is still narrow and is a separate widening topic. write_no_reuse_object()'s return type and the hashfile API are still narrow but unchanged in observable behaviour: on 64-bit Linux ulong coincides with size_t, and on Windows these were the narrow fenceposts the prior topics deliberately left in place. Their widening is left to follow-ups touching the hashfile API and the write_object() caller chain. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- builtin/pack-objects.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 1bf04cd5fa..0ae3bb10af 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -381,11 +381,11 @@ static void *get_delta(struct object_entry *entry) return delta_buf; } -static unsigned long do_compress(void **pptr, unsigned long size) +static size_t do_compress(void **pptr, size_t size) { git_zstream stream; void *in, *out; - unsigned long maxsize; + size_t maxsize; struct repo_config_values *cfg = repo_config_values(the_repository); git_deflate_init(&stream, cfg->pack_compression_level); @@ -511,7 +511,7 @@ static inline int oe_size_greater_than(struct packing_data *pack, static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry, unsigned long limit, int usable_delta) { - unsigned long size, datalen; + size_t size, datalen; unsigned char header[MAX_PACK_OBJECT_HEADER], dheader[MAX_PACK_OBJECT_HEADER]; unsigned hdrlen; @@ -530,11 +530,9 @@ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_ent type = st->type; size = st->size; } else { - size_t size_st = 0; buf = odb_read_object(the_repository->objects, &entry->idx.oid, &type, - &size_st); - size = cast_size_t_to_ulong(size_st); + &size); if (!buf) die(_("unable to read %s"), oid_to_hex(&entry->idx.oid)); From 8849de1945b2eeb98a61f070cb9bd6ab99bc12c3 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 22:23:09 +0200 Subject: [PATCH 4/7] blame: widen struct blame_scoreboard.final_buf_size to size_t Continue the size_t evacuation. final_buf_size is fed either from textconv_object()'s now-size_t out-parameter, from odb_read_object()'s size_t out-parameter (both bridged today through a final_buf_size_st local + cast_size_t_to_ulong()), or from o->file.size (mmfile_t, long). Widen the struct field, point both producers straight at it, and drop the bridge variable along with the cast. builtin/blame.c only reads the field for pointer arithmetic and comparisons, which promote cleanly. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- blame.c | 6 ++---- blame.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/blame.c b/blame.c index 888dec1a38..34380a6fb8 100644 --- a/blame.c +++ b/blame.c @@ -2861,20 +2861,18 @@ void setup_scoreboard(struct blame_scoreboard *sb, sb->final_buf_size = o->file.size; } else { - size_t final_buf_size_st = 0; o = get_origin(sb->final, sb->path); if (fill_blob_sha1_and_mode(sb->repo, o)) die(_("no such path %s in %s"), sb->path, final_commit_name); if (sb->revs->diffopt.flags.allow_textconv && textconv_object(sb->repo, sb->path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf, - &final_buf_size_st)) + &sb->final_buf_size)) ; else sb->final_buf = odb_read_object(the_repository->objects, &o->blob_oid, &type, - &final_buf_size_st); - sb->final_buf_size = cast_size_t_to_ulong(final_buf_size_st); + &sb->final_buf_size); if (!sb->final_buf) die(_("cannot read blob %s for path %s"), diff --git a/blame.h b/blame.h index 3b34be0e5c..1b66084a8d 100644 --- a/blame.h +++ b/blame.h @@ -117,7 +117,7 @@ struct blame_scoreboard { * indexed with scoreboard.lineno[blame_entry.lno]. */ char *final_buf; - unsigned long final_buf_size; + size_t final_buf_size; /* linked list of blames */ struct blame_entry *ent; From e9aa08fde6cd4a404bde7084a160c523e35b8528 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 22:37:32 +0200 Subject: [PATCH 5/7] fast-import: drop the six size casts in the object-read paths Continue the size_t evacuation. fast-import's helper gfi_unpack_entry() and the five size-handling sites that feed off it (store_object()'s deltalen, load_tree(), parse_from_existing(), the inline gfi_unpack_entry() caller in parse_objectish(), cat_blob(), and dereference()) all carry size_t-shaped values from the odb / unpack_entry() APIs through cast_size_t_to_ulong() bridges into unsigned long locals. With the producers (odb_read_object(), odb_read_object_peeled(), unpack_entry()) and the consumers it feeds (the zlib avail_in field from a prior commit, encode_in_pack_object_header()'s uintmax_t parameter, parse_from_commit()'s widened size parameter) all size_t-ready, the bridges and casts go away in one pass. gfi_unpack_entry() now writes into the caller's size_t directly, and the six locals collapse to plain size_t declarations. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- builtin/fast-import.c | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/builtin/fast-import.c b/builtin/fast-import.c index cef98d8fde..b0e79f8c0f 100644 --- a/builtin/fast-import.c +++ b/builtin/fast-import.c @@ -962,7 +962,7 @@ static int store_object( struct object_entry *e; unsigned char hdr[96]; struct object_id oid; - unsigned long hdrlen, deltalen; + size_t hdrlen, deltalen; struct git_hash_ctx c; git_zstream s; struct repo_config_values *cfg = repo_config_values(the_repository); @@ -998,13 +998,10 @@ static int store_object( if (last && last->data.len && last->data.buf && last->depth < max_depth && dat->len > the_hash_algo->rawsz) { - size_t deltalen_st = 0; - delta_count_attempts_by_type[type]++; delta = diff_delta(last->data.buf, last->data.len, dat->buf, dat->len, - &deltalen_st, dat->len - the_hash_algo->rawsz); - deltalen = cast_size_t_to_ulong(deltalen_st); + &deltalen, dat->len - the_hash_algo->rawsz); } else delta = NULL; @@ -1240,10 +1237,9 @@ out: */ static void *gfi_unpack_entry( struct object_entry *oe, - unsigned long *sizep) + size_t *sizep) { enum object_type type; - size_t size_st = 0; void *data; struct packed_git *p = all_packs[oe->pack_id]; if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) { @@ -1266,9 +1262,7 @@ static void *gfi_unpack_entry( */ p->pack_size = pack_size + the_hash_algo->rawsz; } - data = unpack_entry(the_repository, p, oe->idx.offset, &type, &size_st); - if (sizep) - *sizep = cast_size_t_to_ulong(size_st); + data = unpack_entry(the_repository, p, oe->idx.offset, &type, sizep); return data; } @@ -1277,7 +1271,7 @@ static void load_tree(struct tree_entry *root) struct object_id *oid = &root->versions[1].oid; struct object_entry *myoe; struct tree_content *t; - unsigned long size; + size_t size; char *buf; const char *c; @@ -1295,10 +1289,8 @@ static void load_tree(struct tree_entry *root) die(_("can't load tree %s"), oid_to_hex(oid)); } else { enum object_type type; - size_t size_st = 0; buf = odb_read_object(the_repository->objects, oid, &type, - &size_st); - size = cast_size_t_to_ulong(size_st); + &size); if (!buf || type != OBJ_TREE) die(_("can't load tree %s"), oid_to_hex(oid)); } @@ -2616,7 +2608,7 @@ static void file_change_deleteall(struct branch *b) b->num_notes = 0; } -static void parse_from_commit(struct branch *b, char *buf, unsigned long size) +static void parse_from_commit(struct branch *b, char *buf, size_t size) { if (!buf || size < the_hash_algo->hexsz + 6) die(_("not a valid commit: %s"), oid_to_hex(&b->oid)); @@ -2633,13 +2625,11 @@ static void parse_from_existing(struct branch *b) oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo); oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo); } else { - unsigned long size; - size_t size_st = 0; + size_t size; char *buf; buf = odb_read_object_peeled(the_repository->objects, &b->oid, - OBJ_COMMIT, &size_st, &b->oid); - size = cast_size_t_to_ulong(size_st); + OBJ_COMMIT, &size, &b->oid); parse_from_commit(b, buf, size); free(buf); } @@ -2668,7 +2658,7 @@ static int parse_objectish(struct branch *b, const char *objectish) if (!oideq(&b->oid, &oe->idx.oid)) { oidcpy(&b->oid, &oe->idx.oid); if (oe->pack_id != MAX_PACK_ID) { - unsigned long size; + size_t size; char *buf = gfi_unpack_entry(oe, &size); parse_from_commit(b, buf, size); free(buf); @@ -3334,15 +3324,13 @@ static void cat_blob_write(const char *buf, unsigned long size) static void cat_blob(struct object_entry *oe, struct object_id *oid) { struct strbuf line = STRBUF_INIT; - unsigned long size; + size_t size; enum object_type type = 0; char *buf; if (!oe || oe->pack_id == MAX_PACK_ID) { - size_t size_st = 0; buf = odb_read_object(the_repository->objects, oid, &type, - &size_st); - size = cast_size_t_to_ulong(size_st); + &size); } else { type = oe->type; buf = gfi_unpack_entry(oe, &size); @@ -3421,7 +3409,7 @@ static void parse_cat_blob(const char *p) static struct object_entry *dereference(struct object_entry *oe, struct object_id *oid) { - unsigned long size; + size_t size; char *buf = NULL; const unsigned hexsz = the_hash_algo->hexsz; @@ -3450,10 +3438,8 @@ static struct object_entry *dereference(struct object_entry *oe, buf = gfi_unpack_entry(oe, &size); } else { enum object_type unused; - size_t size_st = 0; buf = odb_read_object(the_repository->objects, oid, - &unused, &size_st); - size = cast_size_t_to_ulong(size_st); + &unused, &size); } if (!buf) die(_("can't load object %s"), oid_to_hex(oid)); From 3796065a3da4c910ea65a4417c7b3b5aa901cd14 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 5 Jun 2026 22:50:00 +0200 Subject: [PATCH 6/7] t/helper/test-pack-deltas: drop the delta_size cast in write_ref_delta() Tidies up the bridge variable introduced in the create_delta() / diff_delta() widening commit earlier in this series. With the test helper's local do_compress() also widened to size_t in pass, the narrowing into the unsigned long delta_size local that compress expected is gone, the size_st bridge is unnecessary, and the cast goes away. encode_in_pack_object_header() takes uintmax_t and hashwrite() takes uint32_t, both unchanged. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin --- t/helper/test-pack-deltas.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c index 959705feca..8b448485fb 100644 --- a/t/helper/test-pack-deltas.c +++ b/t/helper/test-pack-deltas.c @@ -18,7 +18,7 @@ static const char *usage_str[] = { NULL }; -static unsigned long do_compress(void **pptr, unsigned long size) +static size_t do_compress(void **pptr, size_t size) { git_zstream stream; void *in, *out; @@ -48,8 +48,8 @@ static void write_ref_delta(struct hashfile *f, struct object_id *base) { unsigned char header[MAX_PACK_OBJECT_HEADER]; - unsigned long delta_size, compressed_size, hdrlen; - size_t size, base_size, delta_size_st = 0; + unsigned long compressed_size, hdrlen; + size_t size, base_size, delta_size; enum object_type type; void *base_buf, *delta_buf; void *buf = odb_read_object(the_repository->objects, @@ -65,8 +65,7 @@ static void write_ref_delta(struct hashfile *f, die("unable to read %s", oid_to_hex(base)); delta_buf = diff_delta(base_buf, base_size, - buf, size, &delta_size_st, 0); - delta_size = cast_size_t_to_ulong(delta_size_st); + buf, size, &delta_size, 0); compressed_size = do_compress(&delta_buf, delta_size); From bd09298afc8a07d076a3ba928d1f7b176df25509 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 22 Jun 2026 11:01:41 +0200 Subject: [PATCH 7/7] Drop the `cast_size_t_to_ulong()` helper Now that all of the call sites of this helper (which I used as a kind of "NEEDSWORK" marker) are eliminated, we can drop that helper altogether. Signed-off-by: Johannes Schindelin --- git-compat-util.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 0fb51b936b..e0f50a277b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -699,15 +699,6 @@ static inline size_t st_left_shift(size_t a, unsigned shift) return a << shift; } -static inline unsigned long cast_size_t_to_ulong(size_t a) -{ - if (a != (unsigned long)a) - die("object too large to read on this platform: %" - PRIuMAX" is cut off to %lu", - (uintmax_t)a, (unsigned long)a); - return (unsigned long)a; -} - static inline uint32_t cast_size_t_to_uint32_t(size_t a) { if (a != (uint32_t)a)