pack-objects: use size_t for in-core object sizes

`pack-objects` stores per-entry object sizes in either the 31-bit `size_` member of the `struct object_entry` or, when the value does not fit, the `pack->delta_size[]` spill array. The accessors (`oe_size`, `oe_delta_size`, `oe_get_size_slow`, `oe_size_*_than`) and the setters (`oe_set_size`, `oe_set_delta_size`) used `unsigned long` for the spill type, which on Windows means the spill silently caps at 4 GiB per entry. That is what made `upload-pack` die with "object too large to read on this platform" when serving the >4 GiB blob in `t5608` tests 5 and 6 when run with `GIT_TEST_CLONE_2GB`. Widen them all to `size_t` (including `pack->delta_size`) and drop the three `cast_size_t_to_ulong()` calls in `check_object()` that guarded `in_pack_size`. The two `SET_SIZE(entry, canonical_size)` calls in the same function stay cast-free as before, since `canonical_size` is still `unsigned long` until a later commit widens `object_info::sizep`. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Jun 15, 2026 at 11:52 UTC 188bac14f7258df67030dd3e244dd4a63a406df5
2 files changed +19 -18
builtin/pack-objects.c
+18 -17
@@ -66,8 +66,8 @@ static inline struct object_entry *oe_delta(
66 return &pack->objects[e->delta_idx - 1];
67 }
68
69 -static inline unsigned long oe_delta_size(struct packing_data *pack,
70 - const struct object_entry *e)
69 +static inline size_t oe_delta_size(struct packing_data *pack,
70 + const struct object_entry *e)
71 {
72 if (e->delta_size_valid)
73 return e->delta_size_;
@@ -83,11 +83,11 @@ static inline unsigned long oe_delta_size(struct packing_data *pack,
83 return pack->delta_size[e - pack->objects];
84 }
85
86 -unsigned long oe_get_size_slow(struct packing_data *pack,
87 - const struct object_entry *e);
86 +size_t oe_get_size_slow(struct packing_data *pack,
87 + const struct object_entry *e);
88
89 -static inline unsigned long oe_size(struct packing_data *pack,
90 - const struct object_entry *e)
89 +static inline size_t oe_size(struct packing_data *pack,
90 + const struct object_entry *e)
91 {
92 if (e->size_valid)
93 return e->size_;
@@ -145,7 +145,7 @@ static inline void oe_set_delta_sibling(struct packing_data *pack,
145
146 static inline void oe_set_size(struct packing_data *pack,
147 struct object_entry *e,
148 - unsigned long size)
148 + size_t size)
149 {
150 if (size < pack->oe_size_limit) {
151 e->size_ = size;
@@ -159,7 +159,7 @@ static inline void oe_set_size(struct packing_data *pack,
159
160 static inline void oe_set_delta_size(struct packing_data *pack,
161 struct object_entry *e,
162 - unsigned long size)
162 + size_t size)
163 {
164 if (size < pack->oe_delta_size_limit) {
165 e->delta_size_ = size;
@@ -496,7 +496,7 @@ static void copy_pack_data(struct hashfile *f,
496
497 static inline int oe_size_greater_than(struct packing_data *pack,
498 const struct object_entry *lhs,
499 - unsigned long rhs)
499 + size_t rhs)
500 {
501 if (lhs->size_valid)
502 return lhs->size_ > rhs;
@@ -2279,7 +2279,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
2279 default:
2280 /* Not a delta hence we've already got all we need. */
2281 oe_set_type(entry, entry->in_pack_type);
2282 - SET_SIZE(entry, cast_size_t_to_ulong(in_pack_size));
2282 + SET_SIZE(entry, in_pack_size);
2283 entry->in_pack_header_size = used;
2284 if (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)
2285 goto give_up;
@@ -2333,8 +2333,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
2333 if (have_base &&
2334 can_reuse_delta(&base_ref, entry, &base_entry)) {
2335 oe_set_type(entry, entry->in_pack_type);
2336 - SET_SIZE(entry, cast_size_t_to_ulong(in_pack_size)); /* delta size */
2337 - SET_DELTA_SIZE(entry, cast_size_t_to_ulong(in_pack_size));
2336 + SET_SIZE(entry, in_pack_size); /* delta size */
2337 + SET_DELTA_SIZE(entry, in_pack_size);
2338
2339 if (base_entry) {
2340 SET_DELTA(entry, base_entry);
@@ -2357,7 +2357,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
2357 * object size from the delta header.
2358 */
2359 delta_pos = entry->in_pack_offset + entry->in_pack_header_size;
2360 - canonical_size = get_size_from_delta(p, &w_curs, delta_pos);
2360 + canonical_size = get_size_from_delta(p, &w_curs,
2361 + delta_pos);
2362 if (canonical_size == 0)
2363 goto give_up;
2364 SET_SIZE(entry, canonical_size);
@@ -2713,7 +2714,7 @@ static pthread_mutex_t progress_mutex;
2714
2715 static inline int oe_size_less_than(struct packing_data *pack,
2716 const struct object_entry *lhs,
2716 - unsigned long rhs)
2717 + size_t rhs)
2718 {
2719 if (lhs->size_valid)
2720 return lhs->size_ < rhs;
@@ -2736,8 +2737,8 @@ static inline void oe_set_tree_depth(struct packing_data *pack,
2737 * reconstruction (so non-deltas are true object sizes, but deltas
2738 * return the size of the delta data).
2739 */
2739 -unsigned long oe_get_size_slow(struct packing_data *pack,
2740 - const struct object_entry *e)
2740 +size_t oe_get_size_slow(struct packing_data *pack,
2741 + const struct object_entry *e)
2742 {
2743 struct packed_git *p;
2744 struct pack_window *w_curs;
@@ -2771,7 +2772,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
2772
2773 unuse_pack(&w_curs);
2774 packing_data_unlock(&to_pack);
2774 - return cast_size_t_to_ulong(size);
2775 + return size;
2776 }
2777
2778 static int try_delta(struct unpacked *trg, struct unpacked *src,
pack-objects.h
+1 -1
@@ -141,7 +141,7 @@ struct packing_data {
141 uint32_t index_size;
142
143 unsigned int *in_pack_pos;
144 - unsigned long *delta_size;
144 + size_t *delta_size;
145
146 /*
147 * Only one of these can be non-NULL and they have different