{"thread":{"id":"65961","subject":"[PATCH 00/12] Next size_t stop: pack-objects/delta","startedAt":"2026-07-09T16:49:42Z","lastAt":"2026-08-13T16:49:48Z","messageCount":55,"participants":["Johannes Schindelin via GitGitGadget","Patrick Steinhardt","Johannes Schindelin","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":12},"messages":[{"id":"547628","messageId":"pull.2175.git.1783615780.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":null,"subject":"[PATCH 00/12] Next size_t stop: pack-objects/delta","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:27Z","receivedAt":"2026-07-09T16:49:42Z","isPatch":true,"body":"This patch series continues the effort to stop using unsigned long where\nsize_t should have been used in the first place. This makes a difference on\n64-bit Windows, where unsigned long is 32-bit.\n\nWith these fixes, the pack-objects machinery works as intended on 64-bit\nWindows (and any other 64-bit platform where unsigned long isn't 64-bit).\n\nJohannes Schindelin (12):\n  diff-delta: widen `struct delta_index`' size fields to `size_t`\n  delta: widen `create_delta_index()` parameter to `size_t`\n  pack-objects: widen delta-cache accounting to `size_t`\n  pack-objects: widen `free_unpacked()` return to `size_t`\n  pack-objects: widen `mem_usage` and `try_delta()`'s out-param to\n    `size_t`\n  delta: widen `create_delta()` and `diff_delta()` to `size_t`\n  packfile, git-zlib: widen `use_pack()` and zstream avail fields to\n    `size_t`\n  archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`\n  diff: widen `deflate_it()`'s bound local from int to `size_t`\n  http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`\n  t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to\n    `size_t`\n  git-zlib: widen `git_deflate_bound()` to `size_t`\n\n archive-zip.c               |  2 +-\n builtin/fast-import.c       |  6 ++++--\n builtin/pack-objects.c      | 30 ++++++++++++++++--------------\n delta.h                     | 12 ++++++------\n diff-delta.c                | 12 ++++++------\n diff.c                      |  6 ++++--\n git-zlib.c                  | 16 ++++++++++++++--\n git-zlib.h                  |  6 +++---\n http-push.c                 |  2 +-\n pack-check.c                |  4 ++--\n packfile.c                  |  4 ++--\n packfile.h                  |  3 ++-\n t/helper/test-delta.c       |  2 +-\n t/helper/test-pack-deltas.c |  7 ++++---\n 14 files changed, 66 insertions(+), 46 deletions(-)\n\n\nbase-commit: f85a7e662054a7b0d9070e432508831afa214b47\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2175%2Fdscho%2Fsize-t%2Fpack-objects-delta-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2175/dscho/size-t/pack-objects-delta-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2175\n-- \ngitgitgadget\n"},{"id":"547629","messageId":"69c2c21f05a2aec95f1ef61f861051c289b03dd4.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 01/12] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:28Z","receivedAt":"2026-07-09T16:49:44Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPreparation for widening the delta-encoding API to `size_t` in\nsubsequent commits, which is what lets pack-objects drop the\n`cast_size_t_to_ulong()` shims that 606c192380 (odb, packfile: use\nsize_t for streaming object sizes, 2026-05-08) had to leave behind in\n`get_delta()` and `try_delta()` because their downstream consumers were\nstill narrow.\n\nThe struct is private to diff-delta.c, so widening its fields in\nisolation is a no-op at runtime: the values stored continue to fit in 32\nbits on Windows because the public API around it still truncates.\nSplitting it out keeps the API-change commit focused on caller updates.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n diff-delta.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/diff-delta.c b/diff-delta.c\nindex 43c339f010..b6b65d7607 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -125,9 +125,9 @@ struct unpacked_index_entry {\n };\n \n struct delta_index {\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \tconst void *src_buf;\n-\tunsigned long src_size;\n+\tsize_t src_size;\n \tunsigned int hash_mask;\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n@@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n \tstruct unpacked_index_entry *entry, **hash;\n \tstruct index_entry *packed_entry, **packed_hash;\n \tvoid *mem;\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \n \tif (!buf || !bufsize)\n \t\treturn NULL;\n-- \ngitgitgadget\n\n"},{"id":"547630","messageId":"d92a5d4dec8a87c412e9dbdb72285e8f7dca61ec.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 02/12] delta: widen `create_delta_index()` parameter to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:29Z","receivedAt":"2026-07-09T16:49:45Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe sole caller (`try_delta()` in builtin/pack-objects.c) passes an\n`unsigned long`, which promotes safely, so no caller fixups are needed.\nSplitting it out keeps the `diff_delta()`/`create_delta()` widening,\nwhich does ripple to several callers, in its own commit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h      | 2 +-\n diff-delta.c | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex eb5c6d2fdb..a19586d789 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -14,7 +14,7 @@ struct delta_index;\n  * using free_delta_index().\n  */\n struct delta_index *\n-create_delta_index(const void *buf, unsigned long bufsize);\n+create_delta_index(const void *buf, size_t bufsize);\n \n /*\n  * free_delta_index: free the index created by create_delta_index()\ndiff --git a/diff-delta.c b/diff-delta.c\nindex b6b65d7607..c93ac42594 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -132,7 +132,7 @@ struct delta_index {\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n \n-struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n+struct delta_index * create_delta_index(const void *buf, size_t bufsize)\n {\n \tunsigned int i, hsize, hmask, entries, prev_val, *hash_count;\n \tconst unsigned char *data, *buffer = buf;\n-- \ngitgitgadget\n\n"},{"id":"547631","messageId":"4ef28865498b33cebc954fccf18a3368f3d114b4.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 03/12] pack-objects: widen delta-cache accounting to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:30Z","receivedAt":"2026-07-09T16:49:47Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThese three are a single accounting tuple (the globals tracking\ncumulative cached-delta bytes, plus the helper that compares them\nagainst an incoming delta size) and are latently 32-bit on Windows where\n`unsigned long` != `size_t`: a pack with many large cached deltas could\nwrap silently.\n\nThe widening is internally consistent on its own: the additions and\nsubtractions against delta_cache_size already come from `size_t` sources\n(`DELTA_SIZE()` returns `size_t`), and `delta_cacheable()`'s sole caller\nin `try_delta()` still passes `unsigned long`, which promotes.\n\nPrerequisite for dropping `try_delta()`'s `cast_size_t_to_ulong()`\nshims, which becomes possible once 1create_delta()` and `diff_delta()`\nare widened in a later commit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex e3760b3492..f89628a760 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;\n \n static int use_delta_islands;\n \n-static unsigned long delta_cache_size = 0;\n-static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n+static size_t delta_cache_size = 0;\n+static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n static unsigned long cache_max_small_delta_size = 1000;\n \n static unsigned long window_memory_limit = 0;\n@@ -2688,8 +2688,8 @@ struct unpacked {\n \tunsigned depth;\n };\n \n-static int delta_cacheable(unsigned long src_size, unsigned long trg_size,\n-\t\t\t   unsigned long delta_size)\n+static int delta_cacheable(size_t src_size, size_t trg_size,\n+\t\t\t   size_t delta_size)\n {\n \tif (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)\n \t\treturn 0;\n-- \ngitgitgadget\n\n"},{"id":"547632","messageId":"07d01200a48c79ba6b3da594d29d685b2c5865d0.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 04/12] pack-objects: widen `free_unpacked()` return to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:31Z","receivedAt":"2026-07-09T16:49:48Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`free_unpacked()` sums two byte counts: `sizeof_delta_index()` and\n`SIZE(n->entry)`. The latter has been `size_t` since the prior topic\n\"More work supporting objects larger than 4GB on Windows\" widened\n`SIZE()`/`oe_size()` to `size_t`, so accumulating it into an `unsigned\nlong` return was a silent Windows-only truncation on a packing run with\nmany large objects.\n\nThe sole caller, `find_deltas()`, still holds its own `mem_usage` in an\n`unsigned long` for now, and therefore still truncates silently.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex f89628a760..4737a6a32c 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2972,9 +2972,9 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)\n \treturn m;\n }\n \n-static unsigned long free_unpacked(struct unpacked *n)\n+static size_t free_unpacked(struct unpacked *n)\n {\n-\tunsigned long freed_mem = sizeof_delta_index(n->index);\n+\tsize_t freed_mem = sizeof_delta_index(n->index);\n \tfree_delta_index(n->index);\n \tn->index = NULL;\n \tif (n->data) {\n-- \ngitgitgadget\n\n"},{"id":"547633","messageId":"7dca16010249768558efc21f522fba8240aeb2f3.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 05/12] pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:32Z","receivedAt":"2026-07-09T16:49:50Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe pair must move together because `find_deltas()` passes `&mem_usage`\nto `try_delta()`: widening either alone breaks the type match.\n\n`mem_usage` accumulates per-object byte counts already computed in\n`size_t` (`SIZE()` and `sizeof_delta_index()` reach here through\n`free_unpacked()`, now `size_t`), and was the last 32-bit-on-Windows\nnarrowing point in the delta-window memory accounting chain. With this\ncommit, that chain uses `size_t` consistently except for\n`sizeof_delta_index()`'s still-narrow return, whose value is bounded by\n`create_delta_index()`'s entries cap.\n\n`window_memory_limit` (config-driven via `git_config_ulong()`) stays\n`unsigned long`: it is only compared against `mem_usage` and promotes.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 4737a6a32c..63ceeb736f 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2804,7 +2804,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n }\n \n static int try_delta(struct unpacked *trg, struct unpacked *src,\n-\t\t     unsigned max_depth, unsigned long *mem_usage)\n+\t\t     unsigned max_depth, size_t *mem_usage)\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n@@ -2991,7 +2991,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,\n {\n \tuint32_t i, idx = 0, count = 0;\n \tstruct unpacked *array;\n-\tunsigned long mem_usage = 0;\n+\tsize_t mem_usage = 0;\n \n \tCALLOC_ARRAY(array, window);\n \n-- \ngitgitgadget\n\n"},{"id":"547634","messageId":"e1ae83ba0378ad5d4278e220584a3fbc37a1dc4e.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 06/12] delta: widen `create_delta()` and `diff_delta()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:33Z","receivedAt":"2026-07-09T16:49:52Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nLast stop in the delta-encoding API widening for >4 GiB blobs on\nWindows: with `create_delta_index()` done in the prior commit and\n`create_delta()`/`diff_delta()` finished here, every byte count that\ncrosses delta.h is now `size_t`. The struct fields they store into have\nbeen `size_t` since the diff-delta struct widening.\n\nThe API change must move with all callers in the same commit (the build\nonly passes when every `&delta_size` matches the new `size_t*`). Caller\nupdates are kept minimal:\n\n  * builtin/pack-objects.c `get_delta()` and `try_delta()`: widen only\n    the local `delta_size` variable; the surrounding unsigned-long\n    locals and their `cast_size_t_to_ulong()` shims are out of scope\n    here and will be cleaned up in their own commits.\n\n  * builtin/fast-import.c, diff.c, t/helper/test-pack-deltas.c:\n    keep the local unsigned-long delta size (each feeds a still-\n    unsigned-long downstream consumer: zlib's `avail_in`,\n    `deflate_it()`, the test helper's own `do_compress()`), and bridge\n    via a temporary `size_t` plus `cast_size_t_to_ulong()`. The new\n    casts are paid back in later topics that widen those consumers.\n\n  * t/helper/test-delta.c: widen the local outright (no downstream\n    consumer beyond the test's own `out_size`, which is already\n    `size_t`).\n\nNote that GCC struggles a bit to figure out that `deltalen` is always\ninitialized before it is used; To help it along, we initialize it to 0.\nThis work-around will go away in a later patch series when `deltalen`\ncan be widened to `size_t`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/fast-import.c       |  6 ++++--\n builtin/pack-objects.c      |  6 ++++--\n delta.h                     | 10 +++++-----\n diff-delta.c                |  4 ++--\n diff.c                      |  4 +++-\n t/helper/test-delta.c       |  2 +-\n t/helper/test-pack-deltas.c |  5 +++--\n 7 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex aa656c5195..1c6e5366c2 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -962,7 +962,7 @@ static int store_object(\n \tstruct object_entry *e;\n \tunsigned char hdr[96];\n \tstruct object_id oid;\n-\tunsigned long hdrlen, deltalen;\n+\tunsigned long hdrlen, deltalen = 0;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n@@ -998,11 +998,13 @@ static int store_object(\n \n \tif (last && last->data.len && last->data.buf && last->depth < max_depth\n \t\t&& dat->len > the_hash_algo->rawsz) {\n+\t\tsize_t deltalen_st;\n \n \t\tdelta_count_attempts_by_type[type]++;\n \t\tdelta = diff_delta(last->data.buf, last->data.len,\n \t\t\tdat->buf, dat->len,\n-\t\t\t&deltalen, dat->len - the_hash_algo->rawsz);\n+\t\t\t&deltalen_st, dat->len - the_hash_algo->rawsz);\n+\t\tdeltalen = cast_size_t_to_ulong(deltalen_st);\n \t} else\n \t\tdelta = NULL;\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 63ceeb736f..315ea0ed7e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -353,7 +353,8 @@ static void index_commit_for_bitmap(struct commit *commit)\n \n static void *get_delta(struct object_entry *entry)\n {\n-\tunsigned long size, base_size, delta_size;\n+\tunsigned long size, base_size;\n+\tsize_t delta_size;\n \tvoid *buf, *base_buf, *delta_buf;\n \tenum object_type type;\n \tsize_t size_st = 0, base_size_st = 0;\n@@ -2808,7 +2809,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n-\tunsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;\n+\tunsigned long trg_size, src_size, sizediff, max_size, sz;\n+\tsize_t delta_size;\n \tunsigned ref_depth;\n \tenum object_type type;\n \tvoid *delta_buf;\ndiff --git a/delta.h b/delta.h\nindex a19586d789..59ccaaa0e0 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -42,8 +42,8 @@ unsigned long sizeof_delta_index(struct delta_index *index);\n  */\n void *\n create_delta(const struct delta_index *index,\n-\t     const void *buf, unsigned long bufsize,\n-\t     unsigned long *delta_size, unsigned long max_delta_size);\n+\t     const void *buf, size_t bufsize,\n+\t     size_t *delta_size, size_t max_delta_size);\n \n /*\n  * diff_delta: create a delta from source buffer to target buffer\n@@ -54,9 +54,9 @@ create_delta(const struct delta_index *index,\n  * updated with its size.  The returned buffer must be freed by the caller.\n  */\n static inline void *\n-diff_delta(const void *src_buf, unsigned long src_bufsize,\n-\t   const void *trg_buf, unsigned long trg_bufsize,\n-\t   unsigned long *delta_size, unsigned long max_delta_size)\n+diff_delta(const void *src_buf, size_t src_bufsize,\n+\t   const void *trg_buf, size_t trg_bufsize,\n+\t   size_t *delta_size, size_t max_delta_size)\n {\n \tstruct delta_index *index = create_delta_index(src_buf, src_bufsize);\n \tif (index) {\ndiff --git a/diff-delta.c b/diff-delta.c\nindex c93ac42594..15210e8381 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -318,8 +318,8 @@ unsigned long sizeof_delta_index(struct delta_index *index)\n \n void *\n create_delta(const struct delta_index *index,\n-\t     const void *trg_buf, unsigned long trg_size,\n-\t     unsigned long *delta_size, unsigned long max_size)\n+\t     const void *trg_buf, size_t trg_size,\n+\t     size_t *delta_size, size_t max_size)\n {\n \tunsigned int i, val;\n \toff_t outpos, moff;\ndiff --git a/diff.c b/diff.c\nindex 2a9d0d8687..69eb2f76a4 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3647,9 +3647,11 @@ static void emit_binary_diff_body(struct diff_options *o,\n \tdelta = NULL;\n \tdeflated = deflate_it(two->ptr, two->size, &deflate_size);\n \tif (one->size && two->size) {\n+\t\tsize_t delta_size_st = 0;\n \t\tdelta = diff_delta(one->ptr, one->size,\n \t\t\t\t   two->ptr, two->size,\n-\t\t\t\t   &delta_size, deflate_size);\n+\t\t\t\t   &delta_size_st, deflate_size);\n+\t\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \t\tif (delta) {\n \t\t\tvoid *to_free = delta;\n \t\t\torig_size = delta_size;\ndiff --git a/t/helper/test-delta.c b/t/helper/test-delta.c\nindex 8223a60229..d807afef75 100644\n--- a/t/helper/test-delta.c\n+++ b/t/helper/test-delta.c\n@@ -32,7 +32,7 @@ int cmd__delta(int argc, const char **argv)\n \t\tdie_errno(\"unable to read '%s'\", argv[3]);\n \n \tif (argv[1][1] == 'd') {\n-\t\tunsigned long delta_size;\n+\t\tsize_t delta_size;\n \t\tout_buf = diff_delta(from.buf, from.len,\n \t\t\t\t     data.buf, data.len,\n \t\t\t\t     &delta_size, 0);\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 840797cf0d..5e0f726842 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -49,7 +49,7 @@ static void write_ref_delta(struct hashfile *f,\n {\n \tunsigned char header[MAX_PACK_OBJECT_HEADER];\n \tunsigned long delta_size, compressed_size, hdrlen;\n-\tsize_t size, base_size;\n+\tsize_t size, base_size, delta_size_st = 0;\n \tenum object_type type;\n \tvoid *base_buf, *delta_buf;\n \tvoid *buf = odb_read_object(the_repository->objects,\n@@ -65,7 +65,8 @@ static void write_ref_delta(struct hashfile *f,\n \t\tdie(\"unable to read %s\", oid_to_hex(base));\n \n \tdelta_buf = diff_delta(base_buf, base_size,\n-\t\t\t       buf, size, &delta_size, 0);\n+\t\t\t       buf, size, &delta_size_st, 0);\n+\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \n \tcompressed_size = do_compress(&delta_buf, delta_size);\n \n-- \ngitgitgadget\n\n"},{"id":"547635","messageId":"8353bc03c175d1eb3618e96832f62562bf6b9976.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 07/12] packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:34Z","receivedAt":"2026-07-09T16:49:53Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nBundling the two widenings: four call sites pass `&stream.avail_in`\ndirectly to `use_pack()`, and widening either type fencepost alone would\nforce a bridge variable at each. Doing both together is the simpler end\nstate and is the prerequisite for the `do_compress()` widening in the\nnext commit, which is what lets `write_no_reuse_object()` lose its last\n`cast_size_t_to_ulong()` shim.\n\nThe unsigned-long locals widened at the other `use_pack()` callers\n(avail / remaining / left) hold pack-window sizes bounded by\n`core.packedGitWindowSize`, so the change is type consistency rather\nthan a new >4GB capability. `git_zstream.avail_in`/`avail_out` likewise\nreach zlib's `uInt` fields only after `zlib_buf_cap()`'s 1 GiB cap, so\nthe wrapper already accepted `size_t`-shaped inputs in practice.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 8 ++++----\n git-zlib.h             | 4 ++--\n pack-check.c           | 4 ++--\n packfile.c             | 4 ++--\n packfile.h             | 3 ++-\n 5 files changed, 12 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 315ea0ed7e..cedda6ba9c 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -488,7 +488,7 @@ static void copy_pack_data(struct hashfile *f,\n \t\toff_t len)\n {\n \tunsigned char *in;\n-\tunsigned long avail;\n+\tsize_t avail;\n \n \twhile (len) {\n \t\tin = use_pack(p, w_curs, offset, &avail);\n@@ -2261,7 +2261,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tstruct object_id base_ref;\n \t\tstruct object_entry *base_entry;\n \t\tunsigned long used, used_0;\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\toff_t ofs;\n \t\tunsigned char *buf, c;\n \t\tenum object_type type;\n@@ -2773,8 +2773,8 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tstruct pack_window *w_curs;\n \tunsigned char *buf;\n \tenum object_type type;\n-\tunsigned long used, avail;\n-\tsize_t size;\n+\tunsigned long used;\n+\tsize_t avail, size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n \t\tsize_t sz;\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 44380e8ad3..0b24b15bd0 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -5,8 +5,8 @@\n \n typedef struct git_zstream {\n \tstruct z_stream_s z;\n-\tunsigned long avail_in;\n-\tunsigned long avail_out;\n+\tsize_t avail_in;\n+\tsize_t avail_out;\n \tsize_t total_in;\n \tsize_t total_out;\n \tunsigned char *next_in;\ndiff --git a/pack-check.c b/pack-check.c\nindex 5adfb3f272..befb860472 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -34,7 +34,7 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,\n \tuint32_t data_crc = crc32(0, NULL, 0);\n \n \tdo {\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\tvoid *data = use_pack(p, w_curs, offset, &avail);\n \t\tif (avail > len)\n \t\t\tavail = len;\n@@ -71,7 +71,7 @@ static int verify_packfile(struct repository *r,\n \n \tr->hash_algo->init_fn(&ctx);\n \tdo {\n-\t\tunsigned long remaining;\n+\t\tsize_t remaining;\n \t\tunsigned char *in = use_pack(p, w_curs, offset, &remaining);\n \t\toffset += remaining;\n \t\tif (!pack_sig_ofs)\ndiff --git a/packfile.c b/packfile.c\nindex 1d1b23b6cc..629fe46a6a 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -620,7 +620,7 @@ static int in_window(struct repository *r, struct pack_window *win,\n unsigned char *use_pack(struct packed_git *p,\n \t\tstruct pack_window **w_cursor,\n \t\toff_t offset,\n-\t\tunsigned long *left)\n+\t\tsize_t *left)\n {\n \tstruct pack_window *win = *w_cursor;\n \n@@ -960,7 +960,7 @@ int unpack_object_header(struct packed_git *p,\n \t\t\t size_t *sizep)\n {\n \tunsigned char *base;\n-\tunsigned long left;\n+\tsize_t left;\n \tunsigned long used;\n \tenum object_type type;\n \ndiff --git a/packfile.h b/packfile.h\nindex 2329a69701..3cff8bdcb9 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -240,7 +240,8 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);\n \n struct object_database;\n \n-unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);\n+unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t,\n+\t\t\tsize_t *);\n void close_pack_windows(struct packed_git *);\n void close_pack(struct packed_git *);\n void unuse_pack(struct pack_window **);\n-- \ngitgitgadget\n\n"},{"id":"547636","messageId":"acffd232acad12f31c6ea685dbc07712e097ecef.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 08/12] archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:35Z","receivedAt":"2026-07-09T16:49:55Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`: the\nlocal that catches its return needs to be `size_t` too, otherwise the\nwidening would introduce a silent Windows narrowing here. No semantic\neffect with the current unsigned-long-returning `git_deflate_bound()`\n(`size_t == unsigned long` on this caller's platforms today).\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n archive-zip.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 97ea8d60d6..a487d4c041 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -206,7 +206,7 @@ static void *zlib_deflate_raw(void *data, unsigned long size,\n \t\t\t      unsigned long *compressed_size)\n {\n \tgit_zstream stream;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \tvoid *buffer;\n \tint result;\n \n-- \ngitgitgadget\n\n"},{"id":"547637","messageId":"b89d28c8aa929dcf4efd40ee8174f5a78aac9eff.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 09/12] diff: widen `deflate_it()`'s bound local from int to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:36Z","receivedAt":"2026-07-09T16:49:57Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nFixes a pre-existing silent narrowing from `git_deflate_bound()`'s\n`unsigned long` return into an `int` local: anything past 2 GiB has\nalways wrapped negative here and then been re-extended to `size_t`\ninside `xmalloc()`. Also prep for the upcoming `git_deflate_bound()`\nwidening to `size_t`, which would extend the narrowing further if\n`bound` stayed `int`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n diff.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 69eb2f76a4..c14f69719b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3609,7 +3609,7 @@ static unsigned char *deflate_it(char *data,\n \t\t\t\t unsigned long size,\n \t\t\t\t unsigned long *result_size)\n {\n-\tint bound;\n+\tsize_t bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n-- \ngitgitgadget\n\n"},{"id":"547638","messageId":"2d4d19c5fbeff50340308b8cffbab21156807b49.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 10/12] http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:37Z","receivedAt":"2026-07-09T16:49:58Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe local is initialised from `git_deflate_bound()` (an unsigned upper\nbound on the deflated output, never negative) and used in exactly three\nplaces: the initialising assignment, `strbuf_grow(buf, size)` whose\nparameter is already `size_t`, and `stream.avail_out` which became\n`size_t` in the prior commit. There is no comparison against zero or a\nnegative value, no subtraction, no arithmetic that depends on\nsignedness, and no path that would assign a signed quantity to it.\n\nThe original `ssize_t` was the wrong type to begin with: a\n`git_deflate_bound()` result above `SSIZE_MAX` would have wrapped\nnegative on assignment and then implicitly re-extended to a huge\n`size_t` at `strbuf_grow()`/`stream.avail_out`, requesting an absurd\nallocation. That is not a real-world concern for the object sizes\nhttp-push pushes today, but it is also the reason the type needs to move\nto `size_t` before `git_deflate_bound()` itself is widened.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http-push.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 3c23cbba27..2a07d14259 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -367,7 +367,7 @@ static void start_put(struct transfer_request *request)\n \tvoid *unpacked;\n \tsize_t len;\n \tint hdrlen;\n-\tssize_t size;\n+\tsize_t size;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-- \ngitgitgadget\n\n"},{"id":"547639","messageId":"617960d9cae58fc621ce846dbc4935bce6bf321e.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 11/12] t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:38Z","receivedAt":"2026-07-09T16:50:00Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`. The\nlocal is only ever the return value of `git_deflate_bound()` and the\n`xmalloc()`/`stream.avail_out` sizes derived from it; widening it has no\nsemantic effect today.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-pack-deltas.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 5e0f726842..959705feca 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -22,7 +22,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n {\n \tgit_zstream stream;\n \tvoid *in, *out;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \n \tgit_deflate_init(&stream, 1);\n \tmaxsize = git_deflate_bound(&stream, size);\n-- \ngitgitgadget\n\n"},{"id":"547640","messageId":"ab911cf55647ed335042f5ac3a6490c36c3ef1d7.1783615780.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH 12/12] git-zlib: widen `git_deflate_bound()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-07-09T16:49:39Z","receivedAt":"2026-07-09T16:50:01Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAll four `unsigned long`/`int`/`ssize_t` receivers across archive-zip,\ndiff, http-push and t/helper/test-pack-deltas were widened to `size_t`\nin the prior commits, and remote-curl and fast-import were already\nthere. With every caller prepared, both the parameter and the return\ntype can now move without introducing any silent narrowing.\n\nFor inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n`uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\nformula (the same fallback it would itself use for an unknown stream\nstate) plus the worst-case wrapper overhead. The existing path through\n`deflateBound()` is unchanged for inputs that fit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-zlib.c | 16 ++++++++++++++--\n git-zlib.h |  2 +-\n 2 files changed, 15 insertions(+), 3 deletions(-)\n\ndiff --git a/git-zlib.c b/git-zlib.c\nindex d21adb3bf5..ebbbcc6d1a 100644\n--- a/git-zlib.c\n+++ b/git-zlib.c\n@@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)\n \treturn status;\n }\n \n-unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)\n+size_t git_deflate_bound(git_zstream *strm, size_t size)\n {\n-\treturn deflateBound(&strm->z, size);\n+#if SIZE_MAX > ULONG_MAX\n+\tif (size > maximum_unsigned_value_of_type(uLong))\n+\t\t/*\n+\t\t * deflateBound() takes uLong, which is 32-bit on\n+\t\t * Windows. For inputs above that range, return zlib's\n+\t\t * stored-block formula (the conservative path it would\n+\t\t * itself use for an unknown stream state) plus the\n+\t\t * worst-case wrapper overhead.\n+\t\t */\n+\t\treturn size + (size >> 5) + (size >> 7) + (size >> 11)\n+\t\t\t+ 7 + 18;\n+#endif\n+\treturn deflateBound(&strm->z, (uLong)size);\n }\n \n void git_deflate_init(git_zstream *strm, int level)\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 0b24b15bd0..9248d11ca9 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -25,6 +25,6 @@ void git_deflate_end(git_zstream *);\n int git_deflate_abort(git_zstream *);\n int git_deflate_end_gently(git_zstream *);\n int git_deflate(git_zstream *, int flush);\n-unsigned long git_deflate_bound(git_zstream *, unsigned long);\n+size_t git_deflate_bound(git_zstream *, size_t);\n \n #endif /* GIT_ZLIB_H */\n-- \ngitgitgadget\n"},{"id":"549664","messageId":"anMA8QmycpIksrQ6@pks.im","threadId":"65961","inReplyTo":"69c2c21f05a2aec95f1ef61f861051c289b03dd4.1783615780.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 01/12] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-05T09:22:57Z","receivedAt":"2026-08-05T09:23:04Z","isPatch":true,"body":"On Thu, Jul 09, 2026 at 04:49:28PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/diff-delta.c b/diff-delta.c\n> index 43c339f010..b6b65d7607 100644\n> --- a/diff-delta.c\n> +++ b/diff-delta.c\n> @@ -125,9 +125,9 @@ struct unpacked_index_entry {\n>  };\n>  \n>  struct delta_index {\n> -\tunsigned long memsize;\n> +\tsize_t memsize;\n>  \tconst void *src_buf;\n> -\tunsigned long src_size;\n> +\tsize_t src_size;\n>  \tunsigned int hash_mask;\n>  \tstruct index_entry *hash[FLEX_ARRAY];\n>  };\n\n`sizeof_delta_index` returns `index->memsize`, so we'll also have to\nadapt that function's return value and its callers.\n\n> @@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n\nI was about to complain that the input parameter here uses `unsigned\nlong`, too. But the next patch addresses that.\n\n>  \tstruct unpacked_index_entry *entry, **hash;\n>  \tstruct index_entry *packed_entry, **packed_hash;\n>  \tvoid *mem;\n> -\tunsigned long memsize;\n> +\tsize_t memsize;\n>  \n>  \tif (!buf || !bufsize)\n>  \t\treturn NULL;\n\nPatrick\n"},{"id":"549665","messageId":"anMA9t5w4386Rm3k@pks.im","threadId":"65961","inReplyTo":"4ef28865498b33cebc954fccf18a3368f3d114b4.1783615780.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 03/12] pack-objects: widen delta-cache accounting to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-05T09:23:02Z","receivedAt":"2026-08-05T09:23:07Z","isPatch":true,"body":"On Thu, Jul 09, 2026 at 04:49:30PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n> index e3760b3492..f89628a760 100644\n> --- a/builtin/pack-objects.c\n> +++ b/builtin/pack-objects.c\n> @@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;\n>  \n>  static int use_delta_islands;\n>  \n> -static unsigned long delta_cache_size = 0;\n> -static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n> +static size_t delta_cache_size = 0;\n> +static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n\nThe only other site that assigns `max_delta_cache_size` does so via\n`git_config_int()`, so we happily accept negative values for\n\"pack.deltacachesize\". This will cause a change in behaviour here, even\nthough arguably the behaviour both before and after this patch is broken\nin the same way.\n\nIdeally we'd have something like `git_config_size_t()`, or at least use\n`git_config_uint()` here. But that could potentially break the case\nwhere somebody mistakenly configured a negative value and took it as\n\"infinite\", which was mostly true before.\n\nIn any case, our docs only mention positive values. So maybe this is\nsomething we could fix while at it.\n\nPatrick\n"},{"id":"549666","messageId":"anMA--V_ec-WPBZq@pks.im","threadId":"65961","inReplyTo":"07d01200a48c79ba6b3da594d29d685b2c5865d0.1783615780.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 04/12] pack-objects: widen `free_unpacked()` return to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-05T09:23:07Z","receivedAt":"2026-08-05T09:23:12Z","isPatch":true,"body":"On Thu, Jul 09, 2026 at 04:49:31PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n> index f89628a760..4737a6a32c 100644\n> --- a/builtin/pack-objects.c\n> +++ b/builtin/pack-objects.c\n> @@ -2972,9 +2972,9 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)\n>  \treturn m;\n>  }\n>  \n> -static unsigned long free_unpacked(struct unpacked *n)\n> +static size_t free_unpacked(struct unpacked *n)\n>  {\n> -\tunsigned long freed_mem = sizeof_delta_index(n->index);\n> +\tsize_t freed_mem = sizeof_delta_index(n->index);\n\nOkay. As mentioned on a preceding patch, the function itself still\nreturns `unsigned long`, which should probably also be corrected in this\npatch series.\n\nPatrick\n"},{"id":"549667","messageId":"anMBAGnkc7dOFsuc@pks.im","threadId":"65961","inReplyTo":"e1ae83ba0378ad5d4278e220584a3fbc37a1dc4e.1783615780.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 06/12] delta: widen `create_delta()` and `diff_delta()` to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-05T09:23:12Z","receivedAt":"2026-08-05T09:23:17Z","isPatch":true,"body":"On Thu, Jul 09, 2026 at 04:49:33PM +0000, Johannes Schindelin via GitGitGadget wrote:\n[snip]\n> Note that GCC struggles a bit to figure out that `deltalen` is always\n> initialized before it is used; To help it along, we initialize it to 0.\n> This work-around will go away in a later patch series when `deltalen`\n> can be widened to `size_t`.\n\nThanks for putting this note here, I was wondering about that part.\n\nPatrick\n"},{"id":"549668","messageId":"anMBBW_arzuri4Qo@pks.im","threadId":"65961","inReplyTo":"ab911cf55647ed335042f5ac3a6490c36c3ef1d7.1783615780.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 12/12] git-zlib: widen `git_deflate_bound()` to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-05T09:23:17Z","receivedAt":"2026-08-05T09:23:22Z","isPatch":true,"body":"On Thu, Jul 09, 2026 at 04:49:39PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> All four `unsigned long`/`int`/`ssize_t` receivers across archive-zip,\n> diff, http-push and t/helper/test-pack-deltas were widened to `size_t`\n> in the prior commits, and remote-curl and fast-import were already\n> there. With every caller prepared, both the parameter and the return\n> type can now move without introducing any silent narrowing.\n\nNit, feel free to ignore: I feel like all of these patches could've been\nsquashed into a single one, as they're trivial enough.\n\n> For inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n> `uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\n> formula (the same fallback it would itself use for an unknown stream\n> state) plus the worst-case wrapper overhead. The existing path through\n> `deflateBound()` is unchanged for inputs that fit.\n\nA link or something like that to the formula would've helped here, as\nI'm not familiar with this mechanism.\n\n> diff --git a/git-zlib.c b/git-zlib.c\n> index d21adb3bf5..ebbbcc6d1a 100644\n> --- a/git-zlib.c\n> +++ b/git-zlib.c\n> @@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)\n>  \treturn status;\n>  }\n>  \n> -unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)\n> +size_t git_deflate_bound(git_zstream *strm, size_t size)\n>  {\n> -\treturn deflateBound(&strm->z, size);\n> +#if SIZE_MAX > ULONG_MAX\n> +\tif (size > maximum_unsigned_value_of_type(uLong))\n> +\t\t/*\n> +\t\t * deflateBound() takes uLong, which is 32-bit on\n> +\t\t * Windows. For inputs above that range, return zlib's\n> +\t\t * stored-block formula (the conservative path it would\n> +\t\t * itself use for an unknown stream state) plus the\n> +\t\t * worst-case wrapper overhead.\n> +\t\t */\n> +\t\treturn size + (size >> 5) + (size >> 7) + (size >> 11)\n> +\t\t\t+ 7 + 18;\n> +#endif\n\nSo is the idea here that we estimate the highest number of bytes that\nthe deflated size could end up with?\n\nPatrick\n"},{"id":"549697","messageId":"2f4a466a-82d0-5a21-d1a6-4482d4d3f841@gmx.de","threadId":"65961","inReplyTo":"anMA8QmycpIksrQ6@pks.im","subject":"Re: [PATCH 01/12] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-08-05T13:51:20Z","receivedAt":"2026-08-05T13:51:23Z","isPatch":true,"body":"Hi Patrick,\n\nOn Wed, 5 Aug 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jul 09, 2026 at 04:49:28PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > diff --git a/diff-delta.c b/diff-delta.c\n> > index 43c339f010..b6b65d7607 100644\n> > --- a/diff-delta.c\n> > +++ b/diff-delta.c\n> > @@ -125,9 +125,9 @@ struct unpacked_index_entry {\n> >  };\n> >  \n> >  struct delta_index {\n> > -\tunsigned long memsize;\n> > +\tsize_t memsize;\n> >  \tconst void *src_buf;\n> > -\tunsigned long src_size;\n> > +\tsize_t src_size;\n> >  \tunsigned int hash_mask;\n> >  \tstruct index_entry *hash[FLEX_ARRAY];\n> >  };\n> \n> `sizeof_delta_index` returns `index->memsize`, so we'll also have to\n> adapt that function's return value and its callers.\n\nGood call! Will fix.\n\nCiao,\nJohannes\n\n> \n> > @@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n> \n> I was about to complain that the input parameter here uses `unsigned\n> long`, too. But the next patch addresses that.\n> \n> >  \tstruct unpacked_index_entry *entry, **hash;\n> >  \tstruct index_entry *packed_entry, **packed_hash;\n> >  \tvoid *mem;\n> > -\tunsigned long memsize;\n> > +\tsize_t memsize;\n> >  \n> >  \tif (!buf || !bufsize)\n> >  \t\treturn NULL;\n> \n> Patrick\n> \n"},{"id":"549698","messageId":"413dc815-10c0-5708-f4de-5c99692e86ff@gmx.de","threadId":"65961","inReplyTo":"anMA9t5w4386Rm3k@pks.im","subject":"Re: [PATCH 03/12] pack-objects: widen delta-cache accounting to `size_t`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-08-05T13:52:56Z","receivedAt":"2026-08-05T13:53:02Z","isPatch":true,"body":"Hi Patrick,\n\nOn Wed, 5 Aug 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jul 09, 2026 at 04:49:30PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\n> > index e3760b3492..f89628a760 100644\n> > --- a/builtin/pack-objects.c\n> > +++ b/builtin/pack-objects.c\n> > @@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;\n> >  \n> >  static int use_delta_islands;\n> >  \n> > -static unsigned long delta_cache_size = 0;\n> > -static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n> > +static size_t delta_cache_size = 0;\n> > +static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n> \n> The only other site that assigns `max_delta_cache_size` does so via\n> `git_config_int()`, so we happily accept negative values for\n> \"pack.deltacachesize\". This will cause a change in behaviour here, even\n> though arguably the behaviour both before and after this patch is broken\n> in the same way.\n> \n> Ideally we'd have something like `git_config_size_t()`, or at least use\n> `git_config_uint()` here.\n\nHeh, I looked for `git_config_size_t()` and it does not exist, but\n`git_config_ssize_t()` exists... Pretty inconsistent. Anyway, I added that\nfunction and use it in the other assignment.\n\nCiao,\nJohannes\n\n> But that could potentially break the case where somebody mistakenly\n> configured a negative value and took it as \"infinite\", which was mostly\n> true before.\n> \n> In any case, our docs only mention positive values. So maybe this is\n> something we could fix while at it.\n> \n> Patrick\n> \n"},{"id":"549699","messageId":"7fe7ca44-f3c4-7e99-b7fe-81e8467e294e@gmx.de","threadId":"65961","inReplyTo":"anMBBW_arzuri4Qo@pks.im","subject":"Re: [PATCH 12/12] git-zlib: widen `git_deflate_bound()` to `size_t`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2026-08-05T13:58:43Z","receivedAt":"2026-08-05T13:58:46Z","isPatch":true,"body":"Hi Patrick,\n\nOn Wed, 5 Aug 2026, Patrick Steinhardt wrote:\n\n> On Thu, Jul 09, 2026 at 04:49:39PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > \n> > All four `unsigned long`/`int`/`ssize_t` receivers across archive-zip,\n> > diff, http-push and t/helper/test-pack-deltas were widened to `size_t`\n> > in the prior commits, and remote-curl and fast-import were already\n> > there. With every caller prepared, both the parameter and the return\n> > type can now move without introducing any silent narrowing.\n> \n> Nit, feel free to ignore: I feel like all of these patches could've been\n> squashed into a single one, as they're trivial enough.\n\nI like them trivial and small ;-)\n\n> > For inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n> > `uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\n> > formula (the same fallback it would itself use for an unknown stream\n> > state) plus the worst-case wrapper overhead. The existing path through\n> > `deflateBound()` is unchanged for inputs that fit.\n> \n> A link or something like that to the formula would've helped here, as\n> I'm not familiar with this mechanism.\n\nRight. I added two references to the commit message.\n\n> \n> > diff --git a/git-zlib.c b/git-zlib.c\n> > index d21adb3bf5..ebbbcc6d1a 100644\n> > --- a/git-zlib.c\n> > +++ b/git-zlib.c\n> > @@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)\n> >  \treturn status;\n> >  }\n> >  \n> > -unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)\n> > +size_t git_deflate_bound(git_zstream *strm, size_t size)\n> >  {\n> > -\treturn deflateBound(&strm->z, size);\n> > +#if SIZE_MAX > ULONG_MAX\n> > +\tif (size > maximum_unsigned_value_of_type(uLong))\n> > +\t\t/*\n> > +\t\t * deflateBound() takes uLong, which is 32-bit on\n> > +\t\t * Windows. For inputs above that range, return zlib's\n> > +\t\t * stored-block formula (the conservative path it would\n> > +\t\t * itself use for an unknown stream state) plus the\n> > +\t\t * worst-case wrapper overhead.\n> > +\t\t */\n> > +\t\treturn size + (size >> 5) + (size >> 7) + (size >> 11)\n> > +\t\t\t+ 7 + 18;\n> > +#endif\n> \n> So is the idea here that we estimate the highest number of bytes that\n> the deflated size could end up with?\n\nPrecisely. And the formula in zlib is a bit complex, it calculates a\n\"fixedlen\" and a \"storelen\" for two different ways to represent the worst\ncase size. But for large values, only `storelen` matters, therefore we can\nget away with a much simpler logic here.\n\nFWIW zlib v1.3.2 added `deflateBound_z()`, which accepts `size_t` (or more\nprecisely: `z_size_t`). However, v1.3.2 is only 7 months old, so I'll be\nretired by the time Debian stable gets it :-P\n\nCiao,\nJohannes\n\n> \n> Patrick\n> \n"},{"id":"549730","messageId":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH v2 00/12] Next size_t stop: pack-objects/delta","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:27Z","receivedAt":"2026-08-05T16:14:44Z","isPatch":true,"body":"This patch series continues the effort to stop using unsigned long where\nsize_t should have been used in the first place. This makes a difference on\n64-bit Windows, where unsigned long is 32-bit.\n\nWith these fixes, the pack-objects machinery works as intended on 64-bit\nWindows (and any other 64-bit platform where unsigned long isn't 64-bit).\n\nChanges since v1:\n\n * The return value of sizeof_delta_index() is now included in the unsigned\n   long -> size_t work.\n * To assign correct values to the now-widened max_delta_cache_size, a new\n   pair of helpers are introduced and used: git_parse_size_t() and\n   git_config_size_t()\n * There are now two references regarding the provenance of the\n   deflateBound() formula in the corresponding commit message.\n\nJohannes Schindelin (12):\n  diff-delta: widen `struct delta_index`' size fields to `size_t`\n  delta: widen `create_delta_index()` parameter to `size_t`\n  pack-objects: widen delta-cache accounting to `size_t`\n  pack-objects: widen `free_unpacked()` return to `size_t`\n  pack-objects: widen `mem_usage` and `try_delta()`'s out-param to\n    `size_t`\n  delta: widen `create_delta()` and `diff_delta()` to `size_t`\n  packfile, git-zlib: widen `use_pack()` and zstream avail fields to\n    `size_t`\n  archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`\n  diff: widen `deflate_it()`'s bound local from int to `size_t`\n  http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`\n  t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to\n    `size_t`\n  git-zlib: widen `git_deflate_bound()` to `size_t`\n\n archive-zip.c               |  2 +-\n builtin/fast-import.c       |  6 ++++--\n builtin/pack-objects.c      | 32 +++++++++++++++++---------------\n config.c                    |  9 +++++++++\n config.h                    |  3 +++\n delta.h                     | 14 +++++++-------\n diff-delta.c                | 14 +++++++-------\n diff.c                      |  6 ++++--\n git-zlib.c                  | 16 ++++++++++++++--\n git-zlib.h                  |  6 +++---\n http-push.c                 |  2 +-\n pack-check.c                |  4 ++--\n packfile.c                  |  4 ++--\n packfile.h                  |  3 ++-\n parse.c                     |  9 +++++++++\n parse.h                     |  1 +\n t/helper/test-delta.c       |  2 +-\n t/helper/test-pack-deltas.c |  7 ++++---\n 18 files changed, 91 insertions(+), 49 deletions(-)\n\n\nbase-commit: f85a7e662054a7b0d9070e432508831afa214b47\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2175%2Fdscho%2Fsize-t%2Fpack-objects-delta-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2175/dscho/size-t/pack-objects-delta-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/2175\n\nRange-diff vs v1:\n\n  1:  69c2c21f05 !  1:  0012c1007b diff-delta: widen `struct delta_index`' size fields to `size_t`\n     @@ Commit message\n          bits on Windows because the public API around it still truncates.\n          Splitting it out keeps the API-change commit focused on caller updates.\n      \n     +    Since the `memsize` attribute is returned by the `sizeof_delta_index()`\n     +    function verbatim, that function's return type is adjusted, too.\n     +\n          Assisted-by: Opus 4.7\n     +    Helped-by: Patrick Steinhardt <ps@pks.im>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n     + ## delta.h ##\n     +@@ delta.h: void free_delta_index(struct delta_index *index);\n     +  *\n     +  * Given pointer must be what create_delta_index() returned, or NULL.\n     +  */\n     +-unsigned long sizeof_delta_index(struct delta_index *index);\n     ++size_t sizeof_delta_index(struct delta_index *index);\n     + \n     + /*\n     +  * create_delta: create a delta from given index for the given buffer\n     +\n       ## diff-delta.c ##\n      @@ diff-delta.c: struct unpacked_index_entry {\n       };\n     @@ diff-delta.c: struct delta_index * create_delta_index(const void *buf, unsigned\n       \n       \tif (!buf || !bufsize)\n       \t\treturn NULL;\n     +@@ diff-delta.c: void free_delta_index(struct delta_index *index)\n     + \tfree(index);\n     + }\n     + \n     +-unsigned long sizeof_delta_index(struct delta_index *index)\n     ++size_t sizeof_delta_index(struct delta_index *index)\n     + {\n     + \tif (index)\n     + \t\treturn index->memsize;\n  2:  d92a5d4dec =  2:  75500c5abb delta: widen `create_delta_index()` parameter to `size_t`\n  3:  4ef2886549 !  3:  5b54041baf pack-objects: widen delta-cache accounting to `size_t`\n     @@ Commit message\n          shims, which becomes possible once 1create_delta()` and `diff_delta()`\n          are widened in a later commit.\n      \n     +    Note: since `max_delta_cache_size` changes data type to `size_t`, a pair\n     +    of new helpers is introduced to parse config values of that type, too.\n     +\n          Assisted-by: Opus 4.7\n     +    Helped-by: Patrick Steinhardt <ps@pks.im>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## builtin/pack-objects.c ##\n     @@ builtin/pack-objects.c: struct unpacked {\n       {\n       \tif (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)\n       \t\treturn 0;\n     +@@ builtin/pack-objects.c: static int git_pack_config(const char *k, const char *v,\n     + \t\treturn 0;\n     + \t}\n     + \tif (!strcmp(k, \"pack.deltacachesize\")) {\n     +-\t\tmax_delta_cache_size = git_config_int(k, v, ctx->kvi);\n     ++\t\tmax_delta_cache_size = git_config_size_t(k, v, ctx->kvi);\n     + \t\treturn 0;\n     + \t}\n     + \tif (!strcmp(k, \"pack.deltacachelimit\")) {\n     +\n     + ## config.c ##\n     +@@ config.c: ssize_t git_config_ssize_t(const char *name, const char *value,\n     + \treturn ret;\n     + }\n     + \n     ++size_t git_config_size_t(const char *name, const char *value,\n     ++\t\t\t const struct key_value_info *kvi)\n     ++{\n     ++\tsize_t ret;\n     ++\tif (!git_parse_size_t(value, &ret))\n     ++\t\tdie_bad_number(name, value, kvi);\n     ++\treturn ret;\n     ++}\n     ++\n     + double git_config_double(const char *name, const char *value,\n     + \t\t\t const struct key_value_info *kvi)\n     + {\n     +\n     + ## config.h ##\n     +@@ config.h: unsigned long git_config_ulong(const char *, const char *,\n     + ssize_t git_config_ssize_t(const char *, const char *,\n     + \t\t\t   const struct key_value_info *);\n     + \n     ++size_t git_config_size_t(const char *, const char *,\n     ++\t\t\t const struct key_value_info *);\n     ++\n     + /**\n     +  * Identically to `git_config_double`, but for double-precision floating point\n     +  * values.\n     +\n     + ## parse.c ##\n     +@@ parse.c: int git_parse_ssize_t(const char *value, ssize_t *ret)\n     + \treturn 1;\n     + }\n     + \n     ++int git_parse_size_t(const char *value, size_t *ret)\n     ++{\n     ++\tuintmax_t tmp;\n     ++\tif (!git_parse_unsigned(value, &tmp, maximum_signed_value_of_type(size_t)))\n     ++\t\treturn 0;\n     ++\t*ret = tmp;\n     ++\treturn 1;\n     ++}\n     ++\n     + int git_parse_double(const char *value, double *ret)\n     + {\n     + \tchar *end;\n     +\n     + ## parse.h ##\n     +@@\n     + int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);\n     + int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max);\n     + int git_parse_ssize_t(const char *, ssize_t *);\n     ++int git_parse_size_t(const char *, size_t *);\n     + int git_parse_ulong(const char *, unsigned long *);\n     + int git_parse_uint(const char *value, unsigned int *ret);\n     + int git_parse_int(const char *value, int *ret);\n  4:  07d01200a4 =  4:  9850de1a91 pack-objects: widen `free_unpacked()` return to `size_t`\n  5:  7dca160102 =  5:  c301958284 pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`\n  6:  e1ae83ba03 !  6:  cfbf6c9567 delta: widen `create_delta()` and `diff_delta()` to `size_t`\n     @@ builtin/pack-objects.c: static int try_delta(struct unpacked *trg, struct unpack\n       \tvoid *delta_buf;\n      \n       ## delta.h ##\n     -@@ delta.h: unsigned long sizeof_delta_index(struct delta_index *index);\n     +@@ delta.h: size_t sizeof_delta_index(struct delta_index *index);\n        */\n       void *\n       create_delta(const struct delta_index *index,\n     @@ delta.h: create_delta(const struct delta_index *index,\n       \tif (index) {\n      \n       ## diff-delta.c ##\n     -@@ diff-delta.c: unsigned long sizeof_delta_index(struct delta_index *index)\n     +@@ diff-delta.c: size_t sizeof_delta_index(struct delta_index *index)\n       \n       void *\n       create_delta(const struct delta_index *index,\n  7:  8353bc03c1 =  7:  ca928b4579 packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`\n  8:  acffd232ac =  8:  9f379ee7aa archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`\n  9:  b89d28c8aa =  9:  ff103a0ee1 diff: widen `deflate_it()`'s bound local from int to `size_t`\n 10:  2d4d19c5fb = 10:  c701d2f9b2 http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`\n 11:  617960d9ca = 11:  e6175d2d87 t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`\n 12:  ab911cf556 ! 12:  762e716afe git-zlib: widen `git_deflate_bound()` to `size_t`\n     @@ Commit message\n      \n          For inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n          `uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\n     -    formula (the same fallback it would itself use for an unknown stream\n     -    state) plus the worst-case wrapper overhead. The existing path through\n     +    formula (the same fallback it would itself use, see\n     +    https://github.com/madler/zlib/blob/v1.3.2/deflate.c#L832-L928 keeping\n     +    in mind that for large sizes, the `storelen` would be relevant, also\n     +    compare with https://github.com/madler/zlib/issues/549 for a fuller\n     +    story) plus the worst-case wrapper overhead. The existing path through\n          `deflateBound()` is unchanged for inputs that fit.\n      \n          Assisted-by: Opus 4.7\n\n-- \ngitgitgadget\n"},{"id":"549731","messageId":"75500c5abbaf5356869f6e465925f2c397c66626.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 02/12] delta: widen `create_delta_index()` parameter to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:29Z","receivedAt":"2026-08-05T16:14:46Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe sole caller (`try_delta()` in builtin/pack-objects.c) passes an\n`unsigned long`, which promotes safely, so no caller fixups are needed.\nSplitting it out keeps the `diff_delta()`/`create_delta()` widening,\nwhich does ripple to several callers, in its own commit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h      | 2 +-\n diff-delta.c | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex ab0279168c..12075c54c5 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -14,7 +14,7 @@ struct delta_index;\n  * using free_delta_index().\n  */\n struct delta_index *\n-create_delta_index(const void *buf, unsigned long bufsize);\n+create_delta_index(const void *buf, size_t bufsize);\n \n /*\n  * free_delta_index: free the index created by create_delta_index()\ndiff --git a/diff-delta.c b/diff-delta.c\nindex 9e1f9e6f95..bcc331af3e 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -132,7 +132,7 @@ struct delta_index {\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n \n-struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n+struct delta_index * create_delta_index(const void *buf, size_t bufsize)\n {\n \tunsigned int i, hsize, hmask, entries, prev_val, *hash_count;\n \tconst unsigned char *data, *buffer = buf;\n-- \ngitgitgadget\n\n"},{"id":"549732","messageId":"0012c1007bc5d0e6ab143a0ab8201456e4f33a24.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 01/12] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:28Z","receivedAt":"2026-08-05T16:14:46Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPreparation for widening the delta-encoding API to `size_t` in\nsubsequent commits, which is what lets pack-objects drop the\n`cast_size_t_to_ulong()` shims that 606c192380 (odb, packfile: use\nsize_t for streaming object sizes, 2026-05-08) had to leave behind in\n`get_delta()` and `try_delta()` because their downstream consumers were\nstill narrow.\n\nThe struct is private to diff-delta.c, so widening its fields in\nisolation is a no-op at runtime: the values stored continue to fit in 32\nbits on Windows because the public API around it still truncates.\nSplitting it out keeps the API-change commit focused on caller updates.\n\nSince the `memsize` attribute is returned by the `sizeof_delta_index()`\nfunction verbatim, that function's return type is adjusted, too.\n\nAssisted-by: Opus 4.7\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h      | 2 +-\n diff-delta.c | 8 ++++----\n 2 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex eb5c6d2fdb..ab0279168c 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -28,7 +28,7 @@ void free_delta_index(struct delta_index *index);\n  *\n  * Given pointer must be what create_delta_index() returned, or NULL.\n  */\n-unsigned long sizeof_delta_index(struct delta_index *index);\n+size_t sizeof_delta_index(struct delta_index *index);\n \n /*\n  * create_delta: create a delta from given index for the given buffer\ndiff --git a/diff-delta.c b/diff-delta.c\nindex 43c339f010..9e1f9e6f95 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -125,9 +125,9 @@ struct unpacked_index_entry {\n };\n \n struct delta_index {\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \tconst void *src_buf;\n-\tunsigned long src_size;\n+\tsize_t src_size;\n \tunsigned int hash_mask;\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n@@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n \tstruct unpacked_index_entry *entry, **hash;\n \tstruct index_entry *packed_entry, **packed_hash;\n \tvoid *mem;\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \n \tif (!buf || !bufsize)\n \t\treturn NULL;\n@@ -302,7 +302,7 @@ void free_delta_index(struct delta_index *index)\n \tfree(index);\n }\n \n-unsigned long sizeof_delta_index(struct delta_index *index)\n+size_t sizeof_delta_index(struct delta_index *index)\n {\n \tif (index)\n \t\treturn index->memsize;\n-- \ngitgitgadget\n\n"},{"id":"549733","messageId":"5b54041bafca1de826ddb4466b3d5d8fcceba3af.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 03/12] pack-objects: widen delta-cache accounting to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:30Z","receivedAt":"2026-08-05T16:14:49Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThese three are a single accounting tuple (the globals tracking\ncumulative cached-delta bytes, plus the helper that compares them\nagainst an incoming delta size) and are latently 32-bit on Windows where\n`unsigned long` != `size_t`: a pack with many large cached deltas could\nwrap silently.\n\nThe widening is internally consistent on its own: the additions and\nsubtractions against delta_cache_size already come from `size_t` sources\n(`DELTA_SIZE()` returns `size_t`), and `delta_cacheable()`'s sole caller\nin `try_delta()` still passes `unsigned long`, which promotes.\n\nPrerequisite for dropping `try_delta()`'s `cast_size_t_to_ulong()`\nshims, which becomes possible once 1create_delta()` and `diff_delta()`\nare widened in a later commit.\n\nNote: since `max_delta_cache_size` changes data type to `size_t`, a pair\nof new helpers is introduced to parse config values of that type, too.\n\nAssisted-by: Opus 4.7\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 10 +++++-----\n config.c               |  9 +++++++++\n config.h               |  3 +++\n parse.c                |  9 +++++++++\n parse.h                |  1 +\n 5 files changed, 27 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex e3760b3492..97246c69ae 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;\n \n static int use_delta_islands;\n \n-static unsigned long delta_cache_size = 0;\n-static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n+static size_t delta_cache_size = 0;\n+static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n static unsigned long cache_max_small_delta_size = 1000;\n \n static unsigned long window_memory_limit = 0;\n@@ -2688,8 +2688,8 @@ struct unpacked {\n \tunsigned depth;\n };\n \n-static int delta_cacheable(unsigned long src_size, unsigned long trg_size,\n-\t\t\t   unsigned long delta_size)\n+static int delta_cacheable(size_t src_size, size_t trg_size,\n+\t\t\t   size_t delta_size)\n {\n \tif (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)\n \t\treturn 0;\n@@ -3701,7 +3701,7 @@ static int git_pack_config(const char *k, const char *v,\n \t\treturn 0;\n \t}\n \tif (!strcmp(k, \"pack.deltacachesize\")) {\n-\t\tmax_delta_cache_size = git_config_int(k, v, ctx->kvi);\n+\t\tmax_delta_cache_size = git_config_size_t(k, v, ctx->kvi);\n \t\treturn 0;\n \t}\n \tif (!strcmp(k, \"pack.deltacachelimit\")) {\ndiff --git a/config.c b/config.c\nindex 6a0de86e3a..010a58d307 100644\n--- a/config.c\n+++ b/config.c\n@@ -1268,6 +1268,15 @@ ssize_t git_config_ssize_t(const char *name, const char *value,\n \treturn ret;\n }\n \n+size_t git_config_size_t(const char *name, const char *value,\n+\t\t\t const struct key_value_info *kvi)\n+{\n+\tsize_t ret;\n+\tif (!git_parse_size_t(value, &ret))\n+\t\tdie_bad_number(name, value, kvi);\n+\treturn ret;\n+}\n+\n double git_config_double(const char *name, const char *value,\n \t\t\t const struct key_value_info *kvi)\n {\ndiff --git a/config.h b/config.h\nindex 31fe3e2961..b66dd08007 100644\n--- a/config.h\n+++ b/config.h\n@@ -282,6 +282,9 @@ unsigned long git_config_ulong(const char *, const char *,\n ssize_t git_config_ssize_t(const char *, const char *,\n \t\t\t   const struct key_value_info *);\n \n+size_t git_config_size_t(const char *, const char *,\n+\t\t\t const struct key_value_info *);\n+\n /**\n  * Identically to `git_config_double`, but for double-precision floating point\n  * values.\ndiff --git a/parse.c b/parse.c\nindex d77f28046a..266bbd539b 100644\n--- a/parse.c\n+++ b/parse.c\n@@ -134,6 +134,15 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)\n \treturn 1;\n }\n \n+int git_parse_size_t(const char *value, size_t *ret)\n+{\n+\tuintmax_t tmp;\n+\tif (!git_parse_unsigned(value, &tmp, maximum_signed_value_of_type(size_t)))\n+\t\treturn 0;\n+\t*ret = tmp;\n+\treturn 1;\n+}\n+\n int git_parse_double(const char *value, double *ret)\n {\n \tchar *end;\ndiff --git a/parse.h b/parse.h\nindex a6dd37c4cb..db742f35fb 100644\n--- a/parse.h\n+++ b/parse.h\n@@ -4,6 +4,7 @@\n int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);\n int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max);\n int git_parse_ssize_t(const char *, ssize_t *);\n+int git_parse_size_t(const char *, size_t *);\n int git_parse_ulong(const char *, unsigned long *);\n int git_parse_uint(const char *value, unsigned int *ret);\n int git_parse_int(const char *value, int *ret);\n-- \ngitgitgadget\n\n"},{"id":"549737","messageId":"c3019582844896d026a092c356b3b1b0e99e3fa8.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 05/12] pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:32Z","receivedAt":"2026-08-05T16:14:53Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe pair must move together because `find_deltas()` passes `&mem_usage`\nto `try_delta()`: widening either alone breaks the type match.\n\n`mem_usage` accumulates per-object byte counts already computed in\n`size_t` (`SIZE()` and `sizeof_delta_index()` reach here through\n`free_unpacked()`, now `size_t`), and was the last 32-bit-on-Windows\nnarrowing point in the delta-window memory accounting chain. With this\ncommit, that chain uses `size_t` consistently except for\n`sizeof_delta_index()`'s still-narrow return, whose value is bounded by\n`create_delta_index()`'s entries cap.\n\n`window_memory_limit` (config-driven via `git_config_ulong()`) stays\n`unsigned long`: it is only compared against `mem_usage` and promotes.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 503ebbf091..96ecee393e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2804,7 +2804,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n }\n \n static int try_delta(struct unpacked *trg, struct unpacked *src,\n-\t\t     unsigned max_depth, unsigned long *mem_usage)\n+\t\t     unsigned max_depth, size_t *mem_usage)\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n@@ -2991,7 +2991,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,\n {\n \tuint32_t i, idx = 0, count = 0;\n \tstruct unpacked *array;\n-\tunsigned long mem_usage = 0;\n+\tsize_t mem_usage = 0;\n \n \tCALLOC_ARRAY(array, window);\n \n-- \ngitgitgadget\n\n"},{"id":"549734","messageId":"9850de1a91c826e673a1dd401c84a4c14c15c317.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 04/12] pack-objects: widen `free_unpacked()` return to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:31Z","receivedAt":"2026-08-05T16:14:54Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`free_unpacked()` sums two byte counts: `sizeof_delta_index()` and\n`SIZE(n->entry)`. The latter has been `size_t` since the prior topic\n\"More work supporting objects larger than 4GB on Windows\" widened\n`SIZE()`/`oe_size()` to `size_t`, so accumulating it into an `unsigned\nlong` return was a silent Windows-only truncation on a packing run with\nmany large objects.\n\nThe sole caller, `find_deltas()`, still holds its own `mem_usage` in an\n`unsigned long` for now, and therefore still truncates silently.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 97246c69ae..503ebbf091 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2972,9 +2972,9 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)\n \treturn m;\n }\n \n-static unsigned long free_unpacked(struct unpacked *n)\n+static size_t free_unpacked(struct unpacked *n)\n {\n-\tunsigned long freed_mem = sizeof_delta_index(n->index);\n+\tsize_t freed_mem = sizeof_delta_index(n->index);\n \tfree_delta_index(n->index);\n \tn->index = NULL;\n \tif (n->data) {\n-- \ngitgitgadget\n\n"},{"id":"549738","messageId":"cfbf6c9567a360f35b27873f66f71a5c94e6a597.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 06/12] delta: widen `create_delta()` and `diff_delta()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:33Z","receivedAt":"2026-08-05T16:14:54Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nLast stop in the delta-encoding API widening for >4 GiB blobs on\nWindows: with `create_delta_index()` done in the prior commit and\n`create_delta()`/`diff_delta()` finished here, every byte count that\ncrosses delta.h is now `size_t`. The struct fields they store into have\nbeen `size_t` since the diff-delta struct widening.\n\nThe API change must move with all callers in the same commit (the build\nonly passes when every `&delta_size` matches the new `size_t*`). Caller\nupdates are kept minimal:\n\n  * builtin/pack-objects.c `get_delta()` and `try_delta()`: widen only\n    the local `delta_size` variable; the surrounding unsigned-long\n    locals and their `cast_size_t_to_ulong()` shims are out of scope\n    here and will be cleaned up in their own commits.\n\n  * builtin/fast-import.c, diff.c, t/helper/test-pack-deltas.c:\n    keep the local unsigned-long delta size (each feeds a still-\n    unsigned-long downstream consumer: zlib's `avail_in`,\n    `deflate_it()`, the test helper's own `do_compress()`), and bridge\n    via a temporary `size_t` plus `cast_size_t_to_ulong()`. The new\n    casts are paid back in later topics that widen those consumers.\n\n  * t/helper/test-delta.c: widen the local outright (no downstream\n    consumer beyond the test's own `out_size`, which is already\n    `size_t`).\n\nNote that GCC struggles a bit to figure out that `deltalen` is always\ninitialized before it is used; To help it along, we initialize it to 0.\nThis work-around will go away in a later patch series when `deltalen`\ncan be widened to `size_t`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/fast-import.c       |  6 ++++--\n builtin/pack-objects.c      |  6 ++++--\n delta.h                     | 10 +++++-----\n diff-delta.c                |  4 ++--\n diff.c                      |  4 +++-\n t/helper/test-delta.c       |  2 +-\n t/helper/test-pack-deltas.c |  5 +++--\n 7 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex aa656c5195..1c6e5366c2 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -962,7 +962,7 @@ static int store_object(\n \tstruct object_entry *e;\n \tunsigned char hdr[96];\n \tstruct object_id oid;\n-\tunsigned long hdrlen, deltalen;\n+\tunsigned long hdrlen, deltalen = 0;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n@@ -998,11 +998,13 @@ static int store_object(\n \n \tif (last && last->data.len && last->data.buf && last->depth < max_depth\n \t\t&& dat->len > the_hash_algo->rawsz) {\n+\t\tsize_t deltalen_st;\n \n \t\tdelta_count_attempts_by_type[type]++;\n \t\tdelta = diff_delta(last->data.buf, last->data.len,\n \t\t\tdat->buf, dat->len,\n-\t\t\t&deltalen, dat->len - the_hash_algo->rawsz);\n+\t\t\t&deltalen_st, dat->len - the_hash_algo->rawsz);\n+\t\tdeltalen = cast_size_t_to_ulong(deltalen_st);\n \t} else\n \t\tdelta = NULL;\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 96ecee393e..08c6d294cc 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -353,7 +353,8 @@ static void index_commit_for_bitmap(struct commit *commit)\n \n static void *get_delta(struct object_entry *entry)\n {\n-\tunsigned long size, base_size, delta_size;\n+\tunsigned long size, base_size;\n+\tsize_t delta_size;\n \tvoid *buf, *base_buf, *delta_buf;\n \tenum object_type type;\n \tsize_t size_st = 0, base_size_st = 0;\n@@ -2808,7 +2809,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n-\tunsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;\n+\tunsigned long trg_size, src_size, sizediff, max_size, sz;\n+\tsize_t delta_size;\n \tunsigned ref_depth;\n \tenum object_type type;\n \tvoid *delta_buf;\ndiff --git a/delta.h b/delta.h\nindex 12075c54c5..42a211905d 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -42,8 +42,8 @@ size_t sizeof_delta_index(struct delta_index *index);\n  */\n void *\n create_delta(const struct delta_index *index,\n-\t     const void *buf, unsigned long bufsize,\n-\t     unsigned long *delta_size, unsigned long max_delta_size);\n+\t     const void *buf, size_t bufsize,\n+\t     size_t *delta_size, size_t max_delta_size);\n \n /*\n  * diff_delta: create a delta from source buffer to target buffer\n@@ -54,9 +54,9 @@ create_delta(const struct delta_index *index,\n  * updated with its size.  The returned buffer must be freed by the caller.\n  */\n static inline void *\n-diff_delta(const void *src_buf, unsigned long src_bufsize,\n-\t   const void *trg_buf, unsigned long trg_bufsize,\n-\t   unsigned long *delta_size, unsigned long max_delta_size)\n+diff_delta(const void *src_buf, size_t src_bufsize,\n+\t   const void *trg_buf, size_t trg_bufsize,\n+\t   size_t *delta_size, size_t max_delta_size)\n {\n \tstruct delta_index *index = create_delta_index(src_buf, src_bufsize);\n \tif (index) {\ndiff --git a/diff-delta.c b/diff-delta.c\nindex bcc331af3e..7cbedeb507 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -318,8 +318,8 @@ size_t sizeof_delta_index(struct delta_index *index)\n \n void *\n create_delta(const struct delta_index *index,\n-\t     const void *trg_buf, unsigned long trg_size,\n-\t     unsigned long *delta_size, unsigned long max_size)\n+\t     const void *trg_buf, size_t trg_size,\n+\t     size_t *delta_size, size_t max_size)\n {\n \tunsigned int i, val;\n \toff_t outpos, moff;\ndiff --git a/diff.c b/diff.c\nindex 2a9d0d8687..69eb2f76a4 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3647,9 +3647,11 @@ static void emit_binary_diff_body(struct diff_options *o,\n \tdelta = NULL;\n \tdeflated = deflate_it(two->ptr, two->size, &deflate_size);\n \tif (one->size && two->size) {\n+\t\tsize_t delta_size_st = 0;\n \t\tdelta = diff_delta(one->ptr, one->size,\n \t\t\t\t   two->ptr, two->size,\n-\t\t\t\t   &delta_size, deflate_size);\n+\t\t\t\t   &delta_size_st, deflate_size);\n+\t\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \t\tif (delta) {\n \t\t\tvoid *to_free = delta;\n \t\t\torig_size = delta_size;\ndiff --git a/t/helper/test-delta.c b/t/helper/test-delta.c\nindex 8223a60229..d807afef75 100644\n--- a/t/helper/test-delta.c\n+++ b/t/helper/test-delta.c\n@@ -32,7 +32,7 @@ int cmd__delta(int argc, const char **argv)\n \t\tdie_errno(\"unable to read '%s'\", argv[3]);\n \n \tif (argv[1][1] == 'd') {\n-\t\tunsigned long delta_size;\n+\t\tsize_t delta_size;\n \t\tout_buf = diff_delta(from.buf, from.len,\n \t\t\t\t     data.buf, data.len,\n \t\t\t\t     &delta_size, 0);\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 840797cf0d..5e0f726842 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -49,7 +49,7 @@ static void write_ref_delta(struct hashfile *f,\n {\n \tunsigned char header[MAX_PACK_OBJECT_HEADER];\n \tunsigned long delta_size, compressed_size, hdrlen;\n-\tsize_t size, base_size;\n+\tsize_t size, base_size, delta_size_st = 0;\n \tenum object_type type;\n \tvoid *base_buf, *delta_buf;\n \tvoid *buf = odb_read_object(the_repository->objects,\n@@ -65,7 +65,8 @@ static void write_ref_delta(struct hashfile *f,\n \t\tdie(\"unable to read %s\", oid_to_hex(base));\n \n \tdelta_buf = diff_delta(base_buf, base_size,\n-\t\t\t       buf, size, &delta_size, 0);\n+\t\t\t       buf, size, &delta_size_st, 0);\n+\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \n \tcompressed_size = do_compress(&delta_buf, delta_size);\n \n-- \ngitgitgadget\n\n"},{"id":"549742","messageId":"ca928b457959ab8bfa643c65f83ca1ec4289fdd3.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 07/12] packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:34Z","receivedAt":"2026-08-05T16:14:56Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nBundling the two widenings: four call sites pass `&stream.avail_in`\ndirectly to `use_pack()`, and widening either type fencepost alone would\nforce a bridge variable at each. Doing both together is the simpler end\nstate and is the prerequisite for the `do_compress()` widening in the\nnext commit, which is what lets `write_no_reuse_object()` lose its last\n`cast_size_t_to_ulong()` shim.\n\nThe unsigned-long locals widened at the other `use_pack()` callers\n(avail / remaining / left) hold pack-window sizes bounded by\n`core.packedGitWindowSize`, so the change is type consistency rather\nthan a new >4GB capability. `git_zstream.avail_in`/`avail_out` likewise\nreach zlib's `uInt` fields only after `zlib_buf_cap()`'s 1 GiB cap, so\nthe wrapper already accepted `size_t`-shaped inputs in practice.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 8 ++++----\n git-zlib.h             | 4 ++--\n pack-check.c           | 4 ++--\n packfile.c             | 4 ++--\n packfile.h             | 3 ++-\n 5 files changed, 12 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 08c6d294cc..87aa8f44e7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -488,7 +488,7 @@ static void copy_pack_data(struct hashfile *f,\n \t\toff_t len)\n {\n \tunsigned char *in;\n-\tunsigned long avail;\n+\tsize_t avail;\n \n \twhile (len) {\n \t\tin = use_pack(p, w_curs, offset, &avail);\n@@ -2261,7 +2261,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tstruct object_id base_ref;\n \t\tstruct object_entry *base_entry;\n \t\tunsigned long used, used_0;\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\toff_t ofs;\n \t\tunsigned char *buf, c;\n \t\tenum object_type type;\n@@ -2773,8 +2773,8 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tstruct pack_window *w_curs;\n \tunsigned char *buf;\n \tenum object_type type;\n-\tunsigned long used, avail;\n-\tsize_t size;\n+\tunsigned long used;\n+\tsize_t avail, size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n \t\tsize_t sz;\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 44380e8ad3..0b24b15bd0 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -5,8 +5,8 @@\n \n typedef struct git_zstream {\n \tstruct z_stream_s z;\n-\tunsigned long avail_in;\n-\tunsigned long avail_out;\n+\tsize_t avail_in;\n+\tsize_t avail_out;\n \tsize_t total_in;\n \tsize_t total_out;\n \tunsigned char *next_in;\ndiff --git a/pack-check.c b/pack-check.c\nindex 5adfb3f272..befb860472 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -34,7 +34,7 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,\n \tuint32_t data_crc = crc32(0, NULL, 0);\n \n \tdo {\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\tvoid *data = use_pack(p, w_curs, offset, &avail);\n \t\tif (avail > len)\n \t\t\tavail = len;\n@@ -71,7 +71,7 @@ static int verify_packfile(struct repository *r,\n \n \tr->hash_algo->init_fn(&ctx);\n \tdo {\n-\t\tunsigned long remaining;\n+\t\tsize_t remaining;\n \t\tunsigned char *in = use_pack(p, w_curs, offset, &remaining);\n \t\toffset += remaining;\n \t\tif (!pack_sig_ofs)\ndiff --git a/packfile.c b/packfile.c\nindex 1d1b23b6cc..629fe46a6a 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -620,7 +620,7 @@ static int in_window(struct repository *r, struct pack_window *win,\n unsigned char *use_pack(struct packed_git *p,\n \t\tstruct pack_window **w_cursor,\n \t\toff_t offset,\n-\t\tunsigned long *left)\n+\t\tsize_t *left)\n {\n \tstruct pack_window *win = *w_cursor;\n \n@@ -960,7 +960,7 @@ int unpack_object_header(struct packed_git *p,\n \t\t\t size_t *sizep)\n {\n \tunsigned char *base;\n-\tunsigned long left;\n+\tsize_t left;\n \tunsigned long used;\n \tenum object_type type;\n \ndiff --git a/packfile.h b/packfile.h\nindex 2329a69701..3cff8bdcb9 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -240,7 +240,8 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);\n \n struct object_database;\n \n-unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);\n+unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t,\n+\t\t\tsize_t *);\n void close_pack_windows(struct packed_git *);\n void close_pack(struct packed_git *);\n void unuse_pack(struct pack_window **);\n-- \ngitgitgadget\n\n"},{"id":"549735","messageId":"ff103a0ee1f99f70b4d7110dc41c184cfd053703.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 09/12] diff: widen `deflate_it()`'s bound local from int to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:36Z","receivedAt":"2026-08-05T16:14:57Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nFixes a pre-existing silent narrowing from `git_deflate_bound()`'s\n`unsigned long` return into an `int` local: anything past 2 GiB has\nalways wrapped negative here and then been re-extended to `size_t`\ninside `xmalloc()`. Also prep for the upcoming `git_deflate_bound()`\nwidening to `size_t`, which would extend the narrowing further if\n`bound` stayed `int`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n diff.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 69eb2f76a4..c14f69719b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3609,7 +3609,7 @@ static unsigned char *deflate_it(char *data,\n \t\t\t\t unsigned long size,\n \t\t\t\t unsigned long *result_size)\n {\n-\tint bound;\n+\tsize_t bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n-- \ngitgitgadget\n\n"},{"id":"549736","messageId":"9f379ee7aa715356ea3377d3e2096df219ea8c76.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 08/12] archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:35Z","receivedAt":"2026-08-05T16:14:58Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`: the\nlocal that catches its return needs to be `size_t` too, otherwise the\nwidening would introduce a silent Windows narrowing here. No semantic\neffect with the current unsigned-long-returning `git_deflate_bound()`\n(`size_t == unsigned long` on this caller's platforms today).\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n archive-zip.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 97ea8d60d6..a487d4c041 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -206,7 +206,7 @@ static void *zlib_deflate_raw(void *data, unsigned long size,\n \t\t\t      unsigned long *compressed_size)\n {\n \tgit_zstream stream;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \tvoid *buffer;\n \tint result;\n \n-- \ngitgitgadget\n\n"},{"id":"549741","messageId":"e6175d2d87e600959a3992aa88075d0dafce5a43.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 11/12] t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:38Z","receivedAt":"2026-08-05T16:15:00Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`. The\nlocal is only ever the return value of `git_deflate_bound()` and the\n`xmalloc()`/`stream.avail_out` sizes derived from it; widening it has no\nsemantic effect today.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-pack-deltas.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 5e0f726842..959705feca 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -22,7 +22,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n {\n \tgit_zstream stream;\n \tvoid *in, *out;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \n \tgit_deflate_init(&stream, 1);\n \tmaxsize = git_deflate_bound(&stream, size);\n-- \ngitgitgadget\n\n"},{"id":"549739","messageId":"c701d2f9b22fcad39ce1713b80570020084ba515.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 10/12] http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:37Z","receivedAt":"2026-08-05T16:15:02Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe local is initialised from `git_deflate_bound()` (an unsigned upper\nbound on the deflated output, never negative) and used in exactly three\nplaces: the initialising assignment, `strbuf_grow(buf, size)` whose\nparameter is already `size_t`, and `stream.avail_out` which became\n`size_t` in the prior commit. There is no comparison against zero or a\nnegative value, no subtraction, no arithmetic that depends on\nsignedness, and no path that would assign a signed quantity to it.\n\nThe original `ssize_t` was the wrong type to begin with: a\n`git_deflate_bound()` result above `SSIZE_MAX` would have wrapped\nnegative on assignment and then implicitly re-extended to a huge\n`size_t` at `strbuf_grow()`/`stream.avail_out`, requesting an absurd\nallocation. That is not a real-world concern for the object sizes\nhttp-push pushes today, but it is also the reason the type needs to move\nto `size_t` before `git_deflate_bound()` itself is widened.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http-push.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 3c23cbba27..2a07d14259 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -367,7 +367,7 @@ static void start_put(struct transfer_request *request)\n \tvoid *unpacked;\n \tsize_t len;\n \tint hdrlen;\n-\tssize_t size;\n+\tsize_t size;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-- \ngitgitgadget\n\n"},{"id":"549740","messageId":"762e716afe2b66b8a58a7c3d26ee9e7876710bf8.1785946479.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"[PATCH v2 12/12] git-zlib: widen `git_deflate_bound()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-05T16:14:39Z","receivedAt":"2026-08-05T16:15:02Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAll four `unsigned long`/`int`/`ssize_t` receivers across archive-zip,\ndiff, http-push and t/helper/test-pack-deltas were widened to `size_t`\nin the prior commits, and remote-curl and fast-import were already\nthere. With every caller prepared, both the parameter and the return\ntype can now move without introducing any silent narrowing.\n\nFor inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n`uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\nformula (the same fallback it would itself use, see\nhttps://github.com/madler/zlib/blob/v1.3.2/deflate.c#L832-L928 keeping\nin mind that for large sizes, the `storelen` would be relevant, also\ncompare with https://github.com/madler/zlib/issues/549 for a fuller\nstory) plus the worst-case wrapper overhead. The existing path through\n`deflateBound()` is unchanged for inputs that fit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-zlib.c | 16 ++++++++++++++--\n git-zlib.h |  2 +-\n 2 files changed, 15 insertions(+), 3 deletions(-)\n\ndiff --git a/git-zlib.c b/git-zlib.c\nindex d21adb3bf5..ebbbcc6d1a 100644\n--- a/git-zlib.c\n+++ b/git-zlib.c\n@@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)\n \treturn status;\n }\n \n-unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)\n+size_t git_deflate_bound(git_zstream *strm, size_t size)\n {\n-\treturn deflateBound(&strm->z, size);\n+#if SIZE_MAX > ULONG_MAX\n+\tif (size > maximum_unsigned_value_of_type(uLong))\n+\t\t/*\n+\t\t * deflateBound() takes uLong, which is 32-bit on\n+\t\t * Windows. For inputs above that range, return zlib's\n+\t\t * stored-block formula (the conservative path it would\n+\t\t * itself use for an unknown stream state) plus the\n+\t\t * worst-case wrapper overhead.\n+\t\t */\n+\t\treturn size + (size >> 5) + (size >> 7) + (size >> 11)\n+\t\t\t+ 7 + 18;\n+#endif\n+\treturn deflateBound(&strm->z, (uLong)size);\n }\n \n void git_deflate_init(git_zstream *strm, int level)\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 0b24b15bd0..9248d11ca9 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -25,6 +25,6 @@ void git_deflate_end(git_zstream *);\n int git_deflate_abort(git_zstream *);\n int git_deflate_end_gently(git_zstream *);\n int git_deflate(git_zstream *, int flush);\n-unsigned long git_deflate_bound(git_zstream *, unsigned long);\n+size_t git_deflate_bound(git_zstream *, size_t);\n \n #endif /* GIT_ZLIB_H */\n-- \ngitgitgadget\n"},{"id":"549789","messageId":"anQmePZ9FcH_Y1nW@pks.im","threadId":"65961","inReplyTo":"0012c1007bc5d0e6ab143a0ab8201456e4f33a24.1785946479.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 01/12] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-06T06:15:20Z","receivedAt":"2026-08-06T06:15:26Z","isPatch":true,"body":"On Wed, Aug 05, 2026 at 04:14:28PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/delta.h b/delta.h\n> index eb5c6d2fdb..ab0279168c 100644\n> --- a/delta.h\n> +++ b/delta.h\n> @@ -28,7 +28,7 @@ void free_delta_index(struct delta_index *index);\n>   *\n>   * Given pointer must be what create_delta_index() returned, or NULL.\n>   */\n> -unsigned long sizeof_delta_index(struct delta_index *index);\n> +size_t sizeof_delta_index(struct delta_index *index);\n>  \n>  /*\n>   * create_delta: create a delta from given index for the given buffer\n\nOkay. At this point in time there's still at least one caller that\nassigns the result of `sizeof_delta_index()` to an `unsigned long`. But\nat the end of the series all callers assign to a `size_t`.\n\nPatrick\n"},{"id":"549790","messageId":"anQmffJEhKxttUjO@pks.im","threadId":"65961","inReplyTo":"pull.2175.v2.git.1785946479.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 00/12] Next size_t stop: pack-objects/delta","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-08-06T06:15:25Z","receivedAt":"2026-08-06T06:15:30Z","isPatch":true,"body":"On Wed, Aug 05, 2026 at 04:14:27PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> Changes since v1:\n> \n>  * The return value of sizeof_delta_index() is now included in the unsigned\n>    long -> size_t work.\n>  * To assign correct values to the now-widened max_delta_cache_size, a new\n>    pair of helpers are introduced and used: git_parse_size_t() and\n>    git_config_size_t()\n>  * There are now two references regarding the provenance of the\n>    deflateBound() formula in the corresponding commit message.\n\nThis addresses all of the comments I had. Thanks!\n\nPatrick\n"},{"id":"549870","messageId":"xmqqy0ejjgwv.fsf@gitster.g","threadId":"65961","inReplyTo":"anQmffJEhKxttUjO@pks.im","subject":"Re: [PATCH v2 00/12] Next size_t stop: pack-objects/delta","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-06T17:30:08Z","receivedAt":"2026-08-06T17:30:12Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Wed, Aug 05, 2026 at 04:14:27PM +0000, Johannes Schindelin via GitGitGadget wrote:\n>> Changes since v1:\n>> \n>>  * The return value of sizeof_delta_index() is now included in the unsigned\n>>    long -> size_t work.\n>>  * To assign correct values to the now-widened max_delta_cache_size, a new\n>>    pair of helpers are introduced and used: git_parse_size_t() and\n>>    git_config_size_t()\n>>  * There are now two references regarding the provenance of the\n>>    deflateBound() formula in the corresponding commit message.\n>\n> This addresses all of the comments I had. Thanks!\n>\n> Patrick\n\nThanks, both.  Shall we mark the topic for 'next'?\n\n"},{"id":"550055","messageId":"xmqqjyq1d2x7.fsf@gitster.g","threadId":"65961","inReplyTo":"ca928b457959ab8bfa643c65f83ca1ec4289fdd3.1785946479.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 07/12] packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-07T21:41:08Z","receivedAt":"2026-08-07T21:41:10Z","isPatch":true,"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> diff --git a/git-zlib.h b/git-zlib.h\n> index 44380e8ad3..0b24b15bd0 100644\n> --- a/git-zlib.h\n> +++ b/git-zlib.h\n> @@ -5,8 +5,8 @@\n>  \n>  typedef struct git_zstream {\n>  \tstruct z_stream_s z;\n> -\tunsigned long avail_in;\n> -\tunsigned long avail_out;\n> +\tsize_t avail_in;\n> +\tsize_t avail_out;\n>  \tsize_t total_in;\n>  \tsize_t total_out;\n>  \tunsigned char *next_in;\n\nWe have these size_t which means we can use a buffer larger than 4GB\nwhere size_t is larger than 32-bit ulong.  But these are sizes of a\nsingle contiguous buffer, so I think that is why the log message\nmentioned that this is more of type consistency than being able to\nhandle larger data (I do not think people feed >4GB contiguious\nbuffer in one go in practice).\n\n - zlib_buf_cap() is still \"unsigned long\", and zlib_pre_call()\n   feeds these potentially wider values to it.  Is it possible that\n   we trigger truncation before the avail_in/avail_out is compared\n   with ZLIB_BUF_MAX in the zlib_buf_cap() function?\n\n - unpack_object_header_buffer() still takes \"unsigned long\" length;\n   builtin/pack-objects.c:oe_get_size_slow() passes size_t avail to\n   unpack_object_header_buffer().  This comes from use_pack(), so it\n   is a relatively small value stored in wider size_t but I am unsure\n   if your static checker would not flag for potential truncation?\n\n"},{"id":"550056","messageId":"xmqqcxvtd1rk.fsf@gitster.g","threadId":"65961","inReplyTo":"ca928b457959ab8bfa643c65f83ca1ec4289fdd3.1785946479.git.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 07/12] packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-07T22:06:07Z","receivedAt":"2026-08-07T22:06:10Z","isPatch":true,"body":"[jc: Sorry, I hit <SEND> before I was ready]\n\n\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> diff --git a/git-zlib.h b/git-zlib.h\n> index 44380e8ad3..0b24b15bd0 100644\n> --- a/git-zlib.h\n> +++ b/git-zlib.h\n> @@ -5,8 +5,8 @@\n>  \n>  typedef struct git_zstream {\n>  \tstruct z_stream_s z;\n> -\tunsigned long avail_in;\n> -\tunsigned long avail_out;\n> +\tsize_t avail_in;\n> +\tsize_t avail_out;\n>  \tsize_t total_in;\n>  \tsize_t total_out;\n>  \tunsigned char *next_in;\n\nWe use 'size_t', which means we can use a buffer larger than 4 GB\non systems where 'size_t' is wider than a 32-bit 'unsigned long'.\nBut these represent the size of a single contiguous buffer, so\nI think that is why the log message mentioned that this is more\nabout type consistency than being able to handle larger data, as\nI do not think anyone would reasonably feed a contiguous buffer\nlarger than 4 GB in one go in practice.  For that reason, two\ndetails stood out to me:\n\n - zlib_buf_cap() still returns 'unsigned long', and\n   zlib_pre_call() feeds these potentially wider values to it.\n   Is it possible that we trigger truncation before 'avail_in'\n   or 'avail_out' is compared with 'ZLIB_BUF_MAX' in\n   zlib_buf_cap()?\n\n - unpack_object_header_buffer() still takes an 'unsigned long'\n   length, while oe_get_size_slow() in 'builtin/pack-objects.c'\n   passes a 'size_t' 'avail' to it.  This comes from use_pack(),\n   so it is a relatively small value stored in a wider 'size_t',\n   but I am unsure whether your static checker would flag this for\n   potential truncation.\n\nThey are probably harmless in practice, but they are still a bit\nconcerning from the standpoint of type consistency.\n"},{"id":"550226","messageId":"xmqqjypx5zyr.fsf@gitster.g","threadId":"65961","inReplyTo":"anQmffJEhKxttUjO@pks.im","subject":"Re: [PATCH v2 00/12] Next size_t stop: pack-objects/delta","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-10T23:15:56Z","receivedAt":"2026-08-10T23:15:59Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Wed, Aug 05, 2026 at 04:14:27PM +0000, Johannes Schindelin via GitGitGadget wrote:\n>> Changes since v1:\n>> \n>>  * The return value of sizeof_delta_index() is now included in the unsigned\n>>    long -> size_t work.\n>>  * To assign correct values to the now-widened max_delta_cache_size, a new\n>>    pair of helpers are introduced and used: git_parse_size_t() and\n>>    git_config_size_t()\n>>  * There are now two references regarding the provenance of the\n>>    deflateBound() formula in the corresponding commit message.\n>\n> This addresses all of the comments I had. Thanks!\n\nOK.  Shall we then mark the topic for 'next'?\n\n    ... goes and looks ...\n\nHmph, some leftover unsigned long assignments I noted in my [07/12]\nreview still disturbs me, though.\n"},{"id":"550511","messageId":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.git.1783615780.gitgitgadget@gmail.com","subject":"[PATCH v3 00/13] Next size_t stop: pack-objects/delta","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:38Z","receivedAt":"2026-08-13T14:55:55Z","isPatch":true,"body":"This patch series continues the effort to stop using unsigned long where\nsize_t should have been used in the first place. This makes a difference on\n64-bit Windows, where unsigned long is 32-bit.\n\nWith these fixes, the pack-objects machinery works as intended on 64-bit\nWindows (and any other 64-bit platform where unsigned long isn't 64-bit).\n\nChanges since v2:\n\n * Now zlib_cap_buf() is also widened in this patch series (I had left this\n   for a later one, originally).\n * The unpack_object_header_buffer() function is now also widened in this\n   here patch series.\n\nChanges since v1:\n\n * The return value of sizeof_delta_index() is now included in the unsigned\n   long -> size_t work.\n * To assign correct values to the now-widened max_delta_cache_size, a new\n   pair of helpers are introduced and used: git_parse_size_t() and\n   git_config_size_t()\n * There are now two references regarding the provenance of the\n   deflateBound() formula in the corresponding commit message.\n\nJohannes Schindelin (13):\n  diff-delta: widen `struct delta_index`' size fields to `size_t`\n  delta: widen `create_delta_index()` parameter to `size_t`\n  pack-objects: widen delta-cache accounting to `size_t`\n  pack-objects: widen `free_unpacked()` return to `size_t`\n  pack-objects: widen `mem_usage` and `try_delta()`'s out-param to\n    `size_t`\n  delta: widen `create_delta()` and `diff_delta()` to `size_t`\n  packfile, git-zlib: widen `use_pack()` and zstream avail fields to\n    `size_t`\n  archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`\n  diff: widen `deflate_it()`'s bound local from int to `size_t`\n  http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`\n  t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to\n    `size_t`\n  git-zlib: widen `git_deflate_bound()` to `size_t`\n  packfile: widen `unpack_object_header_buffer()` to `size_t`\n\n archive-zip.c                |  2 +-\n builtin/fast-import.c        |  6 ++++--\n builtin/pack-objects.c       | 32 ++++++++++++++++----------------\n config.c                     |  9 +++++++++\n config.h                     |  3 +++\n delta.h                      | 14 +++++++-------\n diff-delta.c                 | 14 +++++++-------\n diff.c                       |  6 ++++--\n git-zlib.c                   | 18 +++++++++++++++---\n git-zlib.h                   |  6 +++---\n http-push.c                  |  2 +-\n oss-fuzz/fuzz-pack-headers.c |  2 +-\n pack-check.c                 |  4 ++--\n packfile.c                   | 12 +++++-------\n packfile.h                   |  6 ++++--\n parse.c                      |  9 +++++++++\n parse.h                      |  1 +\n t/helper/test-delta.c        |  2 +-\n t/helper/test-pack-deltas.c  |  7 ++++---\n 19 files changed, 97 insertions(+), 58 deletions(-)\n\n\nbase-commit: f85a7e662054a7b0d9070e432508831afa214b47\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2175%2Fdscho%2Fsize-t%2Fpack-objects-delta-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2175/dscho/size-t/pack-objects-delta-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/2175\n\nRange-diff vs v2:\n\n  1:  0012c1007b =  1:  0012c1007b diff-delta: widen `struct delta_index`' size fields to `size_t`\n  2:  75500c5abb =  2:  75500c5abb delta: widen `create_delta_index()` parameter to `size_t`\n  3:  5b54041baf =  3:  5b54041baf pack-objects: widen delta-cache accounting to `size_t`\n  4:  9850de1a91 =  4:  9850de1a91 pack-objects: widen `free_unpacked()` return to `size_t`\n  5:  c301958284 =  5:  c301958284 pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`\n  6:  cfbf6c9567 =  6:  cfbf6c9567 delta: widen `create_delta()` and `diff_delta()` to `size_t`\n  7:  ca928b4579 !  7:  e4528f9034 packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`\n     @@ builtin/pack-objects.c: size_t oe_get_size_slow(struct packing_data *pack,\n       \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n       \t\tsize_t sz;\n      \n     + ## git-zlib.c ##\n     +@@ git-zlib.c: static const char *zerr_to_string(int status)\n     + \n     + /* uLong is 32-bit on Windows, even on 64-bit systems */\n     + #define ULONG_MAX_VALUE maximum_unsigned_value_of_type(uLong)\n     +-static inline uInt zlib_buf_cap(unsigned long len)\n     ++static inline uInt zlib_buf_cap(size_t len)\n     + {\n     + \treturn (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len;\n     + }\n     +\n       ## git-zlib.h ##\n      @@\n       \n  8:  9f379ee7aa =  8:  4521a41ff6 archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`\n  9:  ff103a0ee1 =  9:  f0765f6ed6 diff: widen `deflate_it()`'s bound local from int to `size_t`\n 10:  c701d2f9b2 = 10:  c91b4d7a7e http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`\n 11:  e6175d2d87 = 11:  f4f2fa75f4 t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`\n 12:  762e716afe = 12:  b4004b1067 git-zlib: widen `git_deflate_bound()` to `size_t`\n  -:  ---------- > 13:  bc4a58336a packfile: widen `unpack_object_header_buffer()` to `size_t`\n\n-- \ngitgitgadget\n"},{"id":"550512","messageId":"0012c1007bc5d0e6ab143a0ab8201456e4f33a24.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 01/13] diff-delta: widen `struct delta_index`' size fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:39Z","receivedAt":"2026-08-13T14:55:56Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPreparation for widening the delta-encoding API to `size_t` in\nsubsequent commits, which is what lets pack-objects drop the\n`cast_size_t_to_ulong()` shims that 606c192380 (odb, packfile: use\nsize_t for streaming object sizes, 2026-05-08) had to leave behind in\n`get_delta()` and `try_delta()` because their downstream consumers were\nstill narrow.\n\nThe struct is private to diff-delta.c, so widening its fields in\nisolation is a no-op at runtime: the values stored continue to fit in 32\nbits on Windows because the public API around it still truncates.\nSplitting it out keeps the API-change commit focused on caller updates.\n\nSince the `memsize` attribute is returned by the `sizeof_delta_index()`\nfunction verbatim, that function's return type is adjusted, too.\n\nAssisted-by: Opus 4.7\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h      | 2 +-\n diff-delta.c | 8 ++++----\n 2 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex eb5c6d2fdb..ab0279168c 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -28,7 +28,7 @@ void free_delta_index(struct delta_index *index);\n  *\n  * Given pointer must be what create_delta_index() returned, or NULL.\n  */\n-unsigned long sizeof_delta_index(struct delta_index *index);\n+size_t sizeof_delta_index(struct delta_index *index);\n \n /*\n  * create_delta: create a delta from given index for the given buffer\ndiff --git a/diff-delta.c b/diff-delta.c\nindex 43c339f010..9e1f9e6f95 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -125,9 +125,9 @@ struct unpacked_index_entry {\n };\n \n struct delta_index {\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \tconst void *src_buf;\n-\tunsigned long src_size;\n+\tsize_t src_size;\n \tunsigned int hash_mask;\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n@@ -140,7 +140,7 @@ struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n \tstruct unpacked_index_entry *entry, **hash;\n \tstruct index_entry *packed_entry, **packed_hash;\n \tvoid *mem;\n-\tunsigned long memsize;\n+\tsize_t memsize;\n \n \tif (!buf || !bufsize)\n \t\treturn NULL;\n@@ -302,7 +302,7 @@ void free_delta_index(struct delta_index *index)\n \tfree(index);\n }\n \n-unsigned long sizeof_delta_index(struct delta_index *index)\n+size_t sizeof_delta_index(struct delta_index *index)\n {\n \tif (index)\n \t\treturn index->memsize;\n-- \ngitgitgadget\n\n"},{"id":"550513","messageId":"75500c5abbaf5356869f6e465925f2c397c66626.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 02/13] delta: widen `create_delta_index()` parameter to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:40Z","receivedAt":"2026-08-13T14:55:58Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe sole caller (`try_delta()` in builtin/pack-objects.c) passes an\n`unsigned long`, which promotes safely, so no caller fixups are needed.\nSplitting it out keeps the `diff_delta()`/`create_delta()` widening,\nwhich does ripple to several callers, in its own commit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n delta.h      | 2 +-\n diff-delta.c | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/delta.h b/delta.h\nindex ab0279168c..12075c54c5 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -14,7 +14,7 @@ struct delta_index;\n  * using free_delta_index().\n  */\n struct delta_index *\n-create_delta_index(const void *buf, unsigned long bufsize);\n+create_delta_index(const void *buf, size_t bufsize);\n \n /*\n  * free_delta_index: free the index created by create_delta_index()\ndiff --git a/diff-delta.c b/diff-delta.c\nindex 9e1f9e6f95..bcc331af3e 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -132,7 +132,7 @@ struct delta_index {\n \tstruct index_entry *hash[FLEX_ARRAY];\n };\n \n-struct delta_index * create_delta_index(const void *buf, unsigned long bufsize)\n+struct delta_index * create_delta_index(const void *buf, size_t bufsize)\n {\n \tunsigned int i, hsize, hmask, entries, prev_val, *hash_count;\n \tconst unsigned char *data, *buffer = buf;\n-- \ngitgitgadget\n\n"},{"id":"550514","messageId":"5b54041bafca1de826ddb4466b3d5d8fcceba3af.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 03/13] pack-objects: widen delta-cache accounting to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:41Z","receivedAt":"2026-08-13T14:55:59Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThese three are a single accounting tuple (the globals tracking\ncumulative cached-delta bytes, plus the helper that compares them\nagainst an incoming delta size) and are latently 32-bit on Windows where\n`unsigned long` != `size_t`: a pack with many large cached deltas could\nwrap silently.\n\nThe widening is internally consistent on its own: the additions and\nsubtractions against delta_cache_size already come from `size_t` sources\n(`DELTA_SIZE()` returns `size_t`), and `delta_cacheable()`'s sole caller\nin `try_delta()` still passes `unsigned long`, which promotes.\n\nPrerequisite for dropping `try_delta()`'s `cast_size_t_to_ulong()`\nshims, which becomes possible once 1create_delta()` and `diff_delta()`\nare widened in a later commit.\n\nNote: since `max_delta_cache_size` changes data type to `size_t`, a pair\nof new helpers is introduced to parse config values of that type, too.\n\nAssisted-by: Opus 4.7\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 10 +++++-----\n config.c               |  9 +++++++++\n config.h               |  3 +++\n parse.c                |  9 +++++++++\n parse.h                |  1 +\n 5 files changed, 27 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex e3760b3492..97246c69ae 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -260,8 +260,8 @@ static int exclude_promisor_objects_best_effort;\n \n static int use_delta_islands;\n \n-static unsigned long delta_cache_size = 0;\n-static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n+static size_t delta_cache_size = 0;\n+static size_t max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;\n static unsigned long cache_max_small_delta_size = 1000;\n \n static unsigned long window_memory_limit = 0;\n@@ -2688,8 +2688,8 @@ struct unpacked {\n \tunsigned depth;\n };\n \n-static int delta_cacheable(unsigned long src_size, unsigned long trg_size,\n-\t\t\t   unsigned long delta_size)\n+static int delta_cacheable(size_t src_size, size_t trg_size,\n+\t\t\t   size_t delta_size)\n {\n \tif (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)\n \t\treturn 0;\n@@ -3701,7 +3701,7 @@ static int git_pack_config(const char *k, const char *v,\n \t\treturn 0;\n \t}\n \tif (!strcmp(k, \"pack.deltacachesize\")) {\n-\t\tmax_delta_cache_size = git_config_int(k, v, ctx->kvi);\n+\t\tmax_delta_cache_size = git_config_size_t(k, v, ctx->kvi);\n \t\treturn 0;\n \t}\n \tif (!strcmp(k, \"pack.deltacachelimit\")) {\ndiff --git a/config.c b/config.c\nindex 6a0de86e3a..010a58d307 100644\n--- a/config.c\n+++ b/config.c\n@@ -1268,6 +1268,15 @@ ssize_t git_config_ssize_t(const char *name, const char *value,\n \treturn ret;\n }\n \n+size_t git_config_size_t(const char *name, const char *value,\n+\t\t\t const struct key_value_info *kvi)\n+{\n+\tsize_t ret;\n+\tif (!git_parse_size_t(value, &ret))\n+\t\tdie_bad_number(name, value, kvi);\n+\treturn ret;\n+}\n+\n double git_config_double(const char *name, const char *value,\n \t\t\t const struct key_value_info *kvi)\n {\ndiff --git a/config.h b/config.h\nindex 31fe3e2961..b66dd08007 100644\n--- a/config.h\n+++ b/config.h\n@@ -282,6 +282,9 @@ unsigned long git_config_ulong(const char *, const char *,\n ssize_t git_config_ssize_t(const char *, const char *,\n \t\t\t   const struct key_value_info *);\n \n+size_t git_config_size_t(const char *, const char *,\n+\t\t\t const struct key_value_info *);\n+\n /**\n  * Identically to `git_config_double`, but for double-precision floating point\n  * values.\ndiff --git a/parse.c b/parse.c\nindex d77f28046a..266bbd539b 100644\n--- a/parse.c\n+++ b/parse.c\n@@ -134,6 +134,15 @@ int git_parse_ssize_t(const char *value, ssize_t *ret)\n \treturn 1;\n }\n \n+int git_parse_size_t(const char *value, size_t *ret)\n+{\n+\tuintmax_t tmp;\n+\tif (!git_parse_unsigned(value, &tmp, maximum_signed_value_of_type(size_t)))\n+\t\treturn 0;\n+\t*ret = tmp;\n+\treturn 1;\n+}\n+\n int git_parse_double(const char *value, double *ret)\n {\n \tchar *end;\ndiff --git a/parse.h b/parse.h\nindex a6dd37c4cb..db742f35fb 100644\n--- a/parse.h\n+++ b/parse.h\n@@ -4,6 +4,7 @@\n int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);\n int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max);\n int git_parse_ssize_t(const char *, ssize_t *);\n+int git_parse_size_t(const char *, size_t *);\n int git_parse_ulong(const char *, unsigned long *);\n int git_parse_uint(const char *value, unsigned int *ret);\n int git_parse_int(const char *value, int *ret);\n-- \ngitgitgadget\n\n"},{"id":"550515","messageId":"9850de1a91c826e673a1dd401c84a4c14c15c317.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 04/13] pack-objects: widen `free_unpacked()` return to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:42Z","receivedAt":"2026-08-13T14:56:01Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\n`free_unpacked()` sums two byte counts: `sizeof_delta_index()` and\n`SIZE(n->entry)`. The latter has been `size_t` since the prior topic\n\"More work supporting objects larger than 4GB on Windows\" widened\n`SIZE()`/`oe_size()` to `size_t`, so accumulating it into an `unsigned\nlong` return was a silent Windows-only truncation on a packing run with\nmany large objects.\n\nThe sole caller, `find_deltas()`, still holds its own `mem_usage` in an\n`unsigned long` for now, and therefore still truncates silently.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 97246c69ae..503ebbf091 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2972,9 +2972,9 @@ static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)\n \treturn m;\n }\n \n-static unsigned long free_unpacked(struct unpacked *n)\n+static size_t free_unpacked(struct unpacked *n)\n {\n-\tunsigned long freed_mem = sizeof_delta_index(n->index);\n+\tsize_t freed_mem = sizeof_delta_index(n->index);\n \tfree_delta_index(n->index);\n \tn->index = NULL;\n \tif (n->data) {\n-- \ngitgitgadget\n\n"},{"id":"550516","messageId":"c3019582844896d026a092c356b3b1b0e99e3fa8.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 05/13] pack-objects: widen `mem_usage` and `try_delta()`'s out-param to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:43Z","receivedAt":"2026-08-13T14:56:03Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe pair must move together because `find_deltas()` passes `&mem_usage`\nto `try_delta()`: widening either alone breaks the type match.\n\n`mem_usage` accumulates per-object byte counts already computed in\n`size_t` (`SIZE()` and `sizeof_delta_index()` reach here through\n`free_unpacked()`, now `size_t`), and was the last 32-bit-on-Windows\nnarrowing point in the delta-window memory accounting chain. With this\ncommit, that chain uses `size_t` consistently except for\n`sizeof_delta_index()`'s still-narrow return, whose value is bounded by\n`create_delta_index()`'s entries cap.\n\n`window_memory_limit` (config-driven via `git_config_ulong()`) stays\n`unsigned long`: it is only compared against `mem_usage` and promotes.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 503ebbf091..96ecee393e 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2804,7 +2804,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n }\n \n static int try_delta(struct unpacked *trg, struct unpacked *src,\n-\t\t     unsigned max_depth, unsigned long *mem_usage)\n+\t\t     unsigned max_depth, size_t *mem_usage)\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n@@ -2991,7 +2991,7 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,\n {\n \tuint32_t i, idx = 0, count = 0;\n \tstruct unpacked *array;\n-\tunsigned long mem_usage = 0;\n+\tsize_t mem_usage = 0;\n \n \tCALLOC_ARRAY(array, window);\n \n-- \ngitgitgadget\n\n"},{"id":"550517","messageId":"e4528f9034099bfd13aa189ba6e4a225389da035.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 07/13] packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:45Z","receivedAt":"2026-08-13T14:56:07Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nBundling the two widenings: four call sites pass `&stream.avail_in`\ndirectly to `use_pack()`, and widening either type fencepost alone would\nforce a bridge variable at each. Doing both together is the simpler end\nstate and is the prerequisite for the `do_compress()` widening in the\nnext commit, which is what lets `write_no_reuse_object()` lose its last\n`cast_size_t_to_ulong()` shim.\n\nThe unsigned-long locals widened at the other `use_pack()` callers\n(avail / remaining / left) hold pack-window sizes bounded by\n`core.packedGitWindowSize`, so the change is type consistency rather\nthan a new >4GB capability. `git_zstream.avail_in`/`avail_out` likewise\nreach zlib's `uInt` fields only after `zlib_buf_cap()`'s 1 GiB cap, so\nthe wrapper already accepted `size_t`-shaped inputs in practice.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c | 8 ++++----\n git-zlib.c             | 2 +-\n git-zlib.h             | 4 ++--\n pack-check.c           | 4 ++--\n packfile.c             | 4 ++--\n packfile.h             | 3 ++-\n 6 files changed, 13 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 08c6d294cc..87aa8f44e7 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -488,7 +488,7 @@ static void copy_pack_data(struct hashfile *f,\n \t\toff_t len)\n {\n \tunsigned char *in;\n-\tunsigned long avail;\n+\tsize_t avail;\n \n \twhile (len) {\n \t\tin = use_pack(p, w_curs, offset, &avail);\n@@ -2261,7 +2261,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tstruct object_id base_ref;\n \t\tstruct object_entry *base_entry;\n \t\tunsigned long used, used_0;\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\toff_t ofs;\n \t\tunsigned char *buf, c;\n \t\tenum object_type type;\n@@ -2773,8 +2773,8 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tstruct pack_window *w_curs;\n \tunsigned char *buf;\n \tenum object_type type;\n-\tunsigned long used, avail;\n-\tsize_t size;\n+\tunsigned long used;\n+\tsize_t avail, size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n \t\tsize_t sz;\ndiff --git a/git-zlib.c b/git-zlib.c\nindex d21adb3bf5..a3b32d9a86 100644\n--- a/git-zlib.c\n+++ b/git-zlib.c\n@@ -33,7 +33,7 @@ static const char *zerr_to_string(int status)\n \n /* uLong is 32-bit on Windows, even on 64-bit systems */\n #define ULONG_MAX_VALUE maximum_unsigned_value_of_type(uLong)\n-static inline uInt zlib_buf_cap(unsigned long len)\n+static inline uInt zlib_buf_cap(size_t len)\n {\n \treturn (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len;\n }\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 44380e8ad3..0b24b15bd0 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -5,8 +5,8 @@\n \n typedef struct git_zstream {\n \tstruct z_stream_s z;\n-\tunsigned long avail_in;\n-\tunsigned long avail_out;\n+\tsize_t avail_in;\n+\tsize_t avail_out;\n \tsize_t total_in;\n \tsize_t total_out;\n \tunsigned char *next_in;\ndiff --git a/pack-check.c b/pack-check.c\nindex 5adfb3f272..befb860472 100644\n--- a/pack-check.c\n+++ b/pack-check.c\n@@ -34,7 +34,7 @@ int check_pack_crc(struct packed_git *p, struct pack_window **w_curs,\n \tuint32_t data_crc = crc32(0, NULL, 0);\n \n \tdo {\n-\t\tunsigned long avail;\n+\t\tsize_t avail;\n \t\tvoid *data = use_pack(p, w_curs, offset, &avail);\n \t\tif (avail > len)\n \t\t\tavail = len;\n@@ -71,7 +71,7 @@ static int verify_packfile(struct repository *r,\n \n \tr->hash_algo->init_fn(&ctx);\n \tdo {\n-\t\tunsigned long remaining;\n+\t\tsize_t remaining;\n \t\tunsigned char *in = use_pack(p, w_curs, offset, &remaining);\n \t\toffset += remaining;\n \t\tif (!pack_sig_ofs)\ndiff --git a/packfile.c b/packfile.c\nindex 1d1b23b6cc..629fe46a6a 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -620,7 +620,7 @@ static int in_window(struct repository *r, struct pack_window *win,\n unsigned char *use_pack(struct packed_git *p,\n \t\tstruct pack_window **w_cursor,\n \t\toff_t offset,\n-\t\tunsigned long *left)\n+\t\tsize_t *left)\n {\n \tstruct pack_window *win = *w_cursor;\n \n@@ -960,7 +960,7 @@ int unpack_object_header(struct packed_git *p,\n \t\t\t size_t *sizep)\n {\n \tunsigned char *base;\n-\tunsigned long left;\n+\tsize_t left;\n \tunsigned long used;\n \tenum object_type type;\n \ndiff --git a/packfile.h b/packfile.h\nindex 2329a69701..3cff8bdcb9 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -240,7 +240,8 @@ uint32_t get_pack_fanout(struct packed_git *p, uint32_t value);\n \n struct object_database;\n \n-unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);\n+unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t,\n+\t\t\tsize_t *);\n void close_pack_windows(struct packed_git *);\n void close_pack(struct packed_git *);\n void unuse_pack(struct pack_window **);\n-- \ngitgitgadget\n\n"},{"id":"550521","messageId":"cfbf6c9567a360f35b27873f66f71a5c94e6a597.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 06/13] delta: widen `create_delta()` and `diff_delta()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:44Z","receivedAt":"2026-08-13T14:56:07Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nLast stop in the delta-encoding API widening for >4 GiB blobs on\nWindows: with `create_delta_index()` done in the prior commit and\n`create_delta()`/`diff_delta()` finished here, every byte count that\ncrosses delta.h is now `size_t`. The struct fields they store into have\nbeen `size_t` since the diff-delta struct widening.\n\nThe API change must move with all callers in the same commit (the build\nonly passes when every `&delta_size` matches the new `size_t*`). Caller\nupdates are kept minimal:\n\n  * builtin/pack-objects.c `get_delta()` and `try_delta()`: widen only\n    the local `delta_size` variable; the surrounding unsigned-long\n    locals and their `cast_size_t_to_ulong()` shims are out of scope\n    here and will be cleaned up in their own commits.\n\n  * builtin/fast-import.c, diff.c, t/helper/test-pack-deltas.c:\n    keep the local unsigned-long delta size (each feeds a still-\n    unsigned-long downstream consumer: zlib's `avail_in`,\n    `deflate_it()`, the test helper's own `do_compress()`), and bridge\n    via a temporary `size_t` plus `cast_size_t_to_ulong()`. The new\n    casts are paid back in later topics that widen those consumers.\n\n  * t/helper/test-delta.c: widen the local outright (no downstream\n    consumer beyond the test's own `out_size`, which is already\n    `size_t`).\n\nNote that GCC struggles a bit to figure out that `deltalen` is always\ninitialized before it is used; To help it along, we initialize it to 0.\nThis work-around will go away in a later patch series when `deltalen`\ncan be widened to `size_t`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/fast-import.c       |  6 ++++--\n builtin/pack-objects.c      |  6 ++++--\n delta.h                     | 10 +++++-----\n diff-delta.c                |  4 ++--\n diff.c                      |  4 +++-\n t/helper/test-delta.c       |  2 +-\n t/helper/test-pack-deltas.c |  5 +++--\n 7 files changed, 22 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex aa656c5195..1c6e5366c2 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -962,7 +962,7 @@ static int store_object(\n \tstruct object_entry *e;\n \tunsigned char hdr[96];\n \tstruct object_id oid;\n-\tunsigned long hdrlen, deltalen;\n+\tunsigned long hdrlen, deltalen = 0;\n \tstruct git_hash_ctx c;\n \tgit_zstream s;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n@@ -998,11 +998,13 @@ static int store_object(\n \n \tif (last && last->data.len && last->data.buf && last->depth < max_depth\n \t\t&& dat->len > the_hash_algo->rawsz) {\n+\t\tsize_t deltalen_st;\n \n \t\tdelta_count_attempts_by_type[type]++;\n \t\tdelta = diff_delta(last->data.buf, last->data.len,\n \t\t\tdat->buf, dat->len,\n-\t\t\t&deltalen, dat->len - the_hash_algo->rawsz);\n+\t\t\t&deltalen_st, dat->len - the_hash_algo->rawsz);\n+\t\tdeltalen = cast_size_t_to_ulong(deltalen_st);\n \t} else\n \t\tdelta = NULL;\n \ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 96ecee393e..08c6d294cc 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -353,7 +353,8 @@ static void index_commit_for_bitmap(struct commit *commit)\n \n static void *get_delta(struct object_entry *entry)\n {\n-\tunsigned long size, base_size, delta_size;\n+\tunsigned long size, base_size;\n+\tsize_t delta_size;\n \tvoid *buf, *base_buf, *delta_buf;\n \tenum object_type type;\n \tsize_t size_st = 0, base_size_st = 0;\n@@ -2808,7 +2809,8 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,\n {\n \tstruct object_entry *trg_entry = trg->entry;\n \tstruct object_entry *src_entry = src->entry;\n-\tunsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;\n+\tunsigned long trg_size, src_size, sizediff, max_size, sz;\n+\tsize_t delta_size;\n \tunsigned ref_depth;\n \tenum object_type type;\n \tvoid *delta_buf;\ndiff --git a/delta.h b/delta.h\nindex 12075c54c5..42a211905d 100644\n--- a/delta.h\n+++ b/delta.h\n@@ -42,8 +42,8 @@ size_t sizeof_delta_index(struct delta_index *index);\n  */\n void *\n create_delta(const struct delta_index *index,\n-\t     const void *buf, unsigned long bufsize,\n-\t     unsigned long *delta_size, unsigned long max_delta_size);\n+\t     const void *buf, size_t bufsize,\n+\t     size_t *delta_size, size_t max_delta_size);\n \n /*\n  * diff_delta: create a delta from source buffer to target buffer\n@@ -54,9 +54,9 @@ create_delta(const struct delta_index *index,\n  * updated with its size.  The returned buffer must be freed by the caller.\n  */\n static inline void *\n-diff_delta(const void *src_buf, unsigned long src_bufsize,\n-\t   const void *trg_buf, unsigned long trg_bufsize,\n-\t   unsigned long *delta_size, unsigned long max_delta_size)\n+diff_delta(const void *src_buf, size_t src_bufsize,\n+\t   const void *trg_buf, size_t trg_bufsize,\n+\t   size_t *delta_size, size_t max_delta_size)\n {\n \tstruct delta_index *index = create_delta_index(src_buf, src_bufsize);\n \tif (index) {\ndiff --git a/diff-delta.c b/diff-delta.c\nindex bcc331af3e..7cbedeb507 100644\n--- a/diff-delta.c\n+++ b/diff-delta.c\n@@ -318,8 +318,8 @@ size_t sizeof_delta_index(struct delta_index *index)\n \n void *\n create_delta(const struct delta_index *index,\n-\t     const void *trg_buf, unsigned long trg_size,\n-\t     unsigned long *delta_size, unsigned long max_size)\n+\t     const void *trg_buf, size_t trg_size,\n+\t     size_t *delta_size, size_t max_size)\n {\n \tunsigned int i, val;\n \toff_t outpos, moff;\ndiff --git a/diff.c b/diff.c\nindex 2a9d0d8687..69eb2f76a4 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3647,9 +3647,11 @@ static void emit_binary_diff_body(struct diff_options *o,\n \tdelta = NULL;\n \tdeflated = deflate_it(two->ptr, two->size, &deflate_size);\n \tif (one->size && two->size) {\n+\t\tsize_t delta_size_st = 0;\n \t\tdelta = diff_delta(one->ptr, one->size,\n \t\t\t\t   two->ptr, two->size,\n-\t\t\t\t   &delta_size, deflate_size);\n+\t\t\t\t   &delta_size_st, deflate_size);\n+\t\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \t\tif (delta) {\n \t\t\tvoid *to_free = delta;\n \t\t\torig_size = delta_size;\ndiff --git a/t/helper/test-delta.c b/t/helper/test-delta.c\nindex 8223a60229..d807afef75 100644\n--- a/t/helper/test-delta.c\n+++ b/t/helper/test-delta.c\n@@ -32,7 +32,7 @@ int cmd__delta(int argc, const char **argv)\n \t\tdie_errno(\"unable to read '%s'\", argv[3]);\n \n \tif (argv[1][1] == 'd') {\n-\t\tunsigned long delta_size;\n+\t\tsize_t delta_size;\n \t\tout_buf = diff_delta(from.buf, from.len,\n \t\t\t\t     data.buf, data.len,\n \t\t\t\t     &delta_size, 0);\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 840797cf0d..5e0f726842 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -49,7 +49,7 @@ static void write_ref_delta(struct hashfile *f,\n {\n \tunsigned char header[MAX_PACK_OBJECT_HEADER];\n \tunsigned long delta_size, compressed_size, hdrlen;\n-\tsize_t size, base_size;\n+\tsize_t size, base_size, delta_size_st = 0;\n \tenum object_type type;\n \tvoid *base_buf, *delta_buf;\n \tvoid *buf = odb_read_object(the_repository->objects,\n@@ -65,7 +65,8 @@ static void write_ref_delta(struct hashfile *f,\n \t\tdie(\"unable to read %s\", oid_to_hex(base));\n \n \tdelta_buf = diff_delta(base_buf, base_size,\n-\t\t\t       buf, size, &delta_size, 0);\n+\t\t\t       buf, size, &delta_size_st, 0);\n+\tdelta_size = cast_size_t_to_ulong(delta_size_st);\n \n \tcompressed_size = do_compress(&delta_buf, delta_size);\n \n-- \ngitgitgadget\n\n"},{"id":"550518","messageId":"4521a41ff6973e87caf4727b37457685d7311b8d.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 08/13] archive-zip: widen `zlib_deflate_raw()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:46Z","receivedAt":"2026-08-13T14:56:09Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`: the\nlocal that catches its return needs to be `size_t` too, otherwise the\nwidening would introduce a silent Windows narrowing here. No semantic\neffect with the current unsigned-long-returning `git_deflate_bound()`\n(`size_t == unsigned long` on this caller's platforms today).\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n archive-zip.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/archive-zip.c b/archive-zip.c\nindex 97ea8d60d6..a487d4c041 100644\n--- a/archive-zip.c\n+++ b/archive-zip.c\n@@ -206,7 +206,7 @@ static void *zlib_deflate_raw(void *data, unsigned long size,\n \t\t\t      unsigned long *compressed_size)\n {\n \tgit_zstream stream;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \tvoid *buffer;\n \tint result;\n \n-- \ngitgitgadget\n\n"},{"id":"550519","messageId":"f0765f6ed6c13c6942f2ae76e5d4065eeb2ef8ce.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 09/13] diff: widen `deflate_it()`'s bound local from int to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:47Z","receivedAt":"2026-08-13T14:56:12Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nFixes a pre-existing silent narrowing from `git_deflate_bound()`'s\n`unsigned long` return into an `int` local: anything past 2 GiB has\nalways wrapped negative here and then been re-extended to `size_t`\ninside `xmalloc()`. Also prep for the upcoming `git_deflate_bound()`\nwidening to `size_t`, which would extend the narrowing further if\n`bound` stayed `int`.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n diff.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 69eb2f76a4..c14f69719b 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -3609,7 +3609,7 @@ static unsigned char *deflate_it(char *data,\n \t\t\t\t unsigned long size,\n \t\t\t\t unsigned long *result_size)\n {\n-\tint bound;\n+\tsize_t bound;\n \tunsigned char *deflated;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n-- \ngitgitgadget\n\n"},{"id":"550520","messageId":"c91b4d7a7e35f48c4b2094614d2c07ccd152ce77.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 10/13] http-push: widen `start_put()`'s size local from `ssize_t` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:48Z","receivedAt":"2026-08-13T14:56:13Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe local is initialised from `git_deflate_bound()` (an unsigned upper\nbound on the deflated output, never negative) and used in exactly three\nplaces: the initialising assignment, `strbuf_grow(buf, size)` whose\nparameter is already `size_t`, and `stream.avail_out` which became\n`size_t` in the prior commit. There is no comparison against zero or a\nnegative value, no subtraction, no arithmetic that depends on\nsignedness, and no path that would assign a signed quantity to it.\n\nThe original `ssize_t` was the wrong type to begin with: a\n`git_deflate_bound()` result above `SSIZE_MAX` would have wrapped\nnegative on assignment and then implicitly re-extended to a huge\n`size_t` at `strbuf_grow()`/`stream.avail_out`, requesting an absurd\nallocation. That is not a real-world concern for the object sizes\nhttp-push pushes today, but it is also the reason the type needs to move\nto `size_t` before `git_deflate_bound()` itself is widened.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n http-push.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/http-push.c b/http-push.c\nindex 3c23cbba27..2a07d14259 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -367,7 +367,7 @@ static void start_put(struct transfer_request *request)\n \tvoid *unpacked;\n \tsize_t len;\n \tint hdrlen;\n-\tssize_t size;\n+\tsize_t size;\n \tgit_zstream stream;\n \tstruct repo_config_values *cfg = repo_config_values(the_repository);\n \n-- \ngitgitgadget\n\n"},{"id":"550523","messageId":"b4004b106709f40ae358246631f5c78ad46aa397.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 12/13] git-zlib: widen `git_deflate_bound()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:50Z","receivedAt":"2026-08-13T14:56:15Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAll four `unsigned long`/`int`/`ssize_t` receivers across archive-zip,\ndiff, http-push and t/helper/test-pack-deltas were widened to `size_t`\nin the prior commits, and remote-curl and fast-import were already\nthere. With every caller prepared, both the parameter and the return\ntype can now move without introducing any silent narrowing.\n\nFor inputs above zlib's `uLong` range (i.e. >4 GiB on platforms where\n`uLong` is 32-bit, notably 64-bit Windows), defer to zlib's stored-block\nformula (the same fallback it would itself use, see\nhttps://github.com/madler/zlib/blob/v1.3.2/deflate.c#L832-L928 keeping\nin mind that for large sizes, the `storelen` would be relevant, also\ncompare with https://github.com/madler/zlib/issues/549 for a fuller\nstory) plus the worst-case wrapper overhead. The existing path through\n`deflateBound()` is unchanged for inputs that fit.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n git-zlib.c | 16 ++++++++++++++--\n git-zlib.h |  2 +-\n 2 files changed, 15 insertions(+), 3 deletions(-)\n\ndiff --git a/git-zlib.c b/git-zlib.c\nindex a3b32d9a86..1c94f90497 100644\n--- a/git-zlib.c\n+++ b/git-zlib.c\n@@ -167,9 +167,21 @@ int git_inflate(git_zstream *strm, int flush)\n \treturn status;\n }\n \n-unsigned long git_deflate_bound(git_zstream *strm, unsigned long size)\n+size_t git_deflate_bound(git_zstream *strm, size_t size)\n {\n-\treturn deflateBound(&strm->z, size);\n+#if SIZE_MAX > ULONG_MAX\n+\tif (size > maximum_unsigned_value_of_type(uLong))\n+\t\t/*\n+\t\t * deflateBound() takes uLong, which is 32-bit on\n+\t\t * Windows. For inputs above that range, return zlib's\n+\t\t * stored-block formula (the conservative path it would\n+\t\t * itself use for an unknown stream state) plus the\n+\t\t * worst-case wrapper overhead.\n+\t\t */\n+\t\treturn size + (size >> 5) + (size >> 7) + (size >> 11)\n+\t\t\t+ 7 + 18;\n+#endif\n+\treturn deflateBound(&strm->z, (uLong)size);\n }\n \n void git_deflate_init(git_zstream *strm, int level)\ndiff --git a/git-zlib.h b/git-zlib.h\nindex 0b24b15bd0..9248d11ca9 100644\n--- a/git-zlib.h\n+++ b/git-zlib.h\n@@ -25,6 +25,6 @@ void git_deflate_end(git_zstream *);\n int git_deflate_abort(git_zstream *);\n int git_deflate_end_gently(git_zstream *);\n int git_deflate(git_zstream *, int flush);\n-unsigned long git_deflate_bound(git_zstream *, unsigned long);\n+size_t git_deflate_bound(git_zstream *, size_t);\n \n #endif /* GIT_ZLIB_H */\n-- \ngitgitgadget\n\n"},{"id":"550522","messageId":"bc4a58336a094052f636786af495adcb84ab24f8.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 13/13] packfile: widen `unpack_object_header_buffer()` to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:51Z","receivedAt":"2026-08-13T14:56:16Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nAs part of the ongoing effort to replace `unsigned long` data types with\n`size_t` wherever appropriate (mainly to fix all those problems on\nWindows with objects larger than 4GB), let's also adjust the return type\nand the type of the `len` parameter of this function.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n builtin/pack-objects.c       |  6 ++----\n oss-fuzz/fuzz-pack-headers.c |  2 +-\n packfile.c                   | 10 ++++------\n packfile.h                   |  3 ++-\n 4 files changed, 9 insertions(+), 12 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 87aa8f44e7..d9922174f1 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2260,8 +2260,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)\n \t\tint have_base = 0;\n \t\tstruct object_id base_ref;\n \t\tstruct object_entry *base_entry;\n-\t\tunsigned long used, used_0;\n-\t\tsize_t avail;\n+\t\tsize_t used, used_0, avail;\n \t\toff_t ofs;\n \t\tunsigned char *buf, c;\n \t\tenum object_type type;\n@@ -2773,8 +2772,7 @@ size_t oe_get_size_slow(struct packing_data *pack,\n \tstruct pack_window *w_curs;\n \tunsigned char *buf;\n \tenum object_type type;\n-\tunsigned long used;\n-\tsize_t avail, size;\n+\tsize_t used, avail, size;\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n \t\tsize_t sz;\ndiff --git a/oss-fuzz/fuzz-pack-headers.c b/oss-fuzz/fuzz-pack-headers.c\nindex ef61ab577c..e44afe0b8d 100644\n--- a/oss-fuzz/fuzz-pack-headers.c\n+++ b/oss-fuzz/fuzz-pack-headers.c\n@@ -9,7 +9,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n \tsize_t len;\n \n \tunpack_object_header_buffer((const unsigned char *)data,\n-\t\t\t\t    (unsigned long)size, &type, &len);\n+\t\t\t\t    size, &type, &len);\n \n \treturn 0;\n }\ndiff --git a/packfile.c b/packfile.c\nindex 629fe46a6a..faecb3cf17 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -866,12 +866,11 @@ struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *s\n \treturn store->packs.head;\n }\n \n-unsigned long unpack_object_header_buffer(const unsigned char *buf,\n-\t\tunsigned long len, enum object_type *type, size_t *sizep)\n+size_t unpack_object_header_buffer(const unsigned char *buf, size_t len,\n+\t\t\t\t   enum object_type *type, size_t *sizep)\n {\n \tunsigned shift;\n-\tsize_t size, c;\n-\tunsigned long used = 0;\n+\tsize_t size, c, used = 0;\n \n \tc = buf[used++];\n \t*type = (c >> 4) & 7;\n@@ -960,8 +959,7 @@ int unpack_object_header(struct packed_git *p,\n \t\t\t size_t *sizep)\n {\n \tunsigned char *base;\n-\tsize_t left;\n-\tunsigned long used;\n+\tsize_t left, used;\n \tenum object_type type;\n \n \t/* use_pack() assures us we have [base, base + 20) available\ndiff --git a/packfile.h b/packfile.h\nindex 3cff8bdcb9..e4e64117fb 100644\n--- a/packfile.h\n+++ b/packfile.h\n@@ -300,7 +300,8 @@ int packfile_fill_entry(struct packed_git *p,\n int is_pack_valid(struct packed_git *);\n void *unpack_entry(struct repository *r, struct packed_git *, off_t,\n \t\t   enum object_type *, size_t *);\n-unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, size_t *sizep);\n+size_t unpack_object_header_buffer(const unsigned char *buf, size_t len,\n+\t\t\t\t   enum object_type *type, size_t *sizep);\n size_t get_size_from_delta(struct packed_git *, struct pack_window **, off_t);\n int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, size_t *);\n off_t get_delta_base(struct packed_git *p, struct pack_window **w_curs,\n-- \ngitgitgadget\n"},{"id":"550524","messageId":"f4f2fa75f4814ccd67501d23743eb90fda35aae3.1786632952.git.gitgitgadget@gmail.com","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"[PATCH v3 11/13] t/helper/test-pack-deltas: widen `do_compress()`'s maxsize local to `size_t`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-08-13T14:55:49Z","receivedAt":"2026-08-13T14:56:16Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nPrep for the upcoming `git_deflate_bound()` widening to `size_t`. The\nlocal is only ever the return value of `git_deflate_bound()` and the\n`xmalloc()`/`stream.avail_out` sizes derived from it; widening it has no\nsemantic effect today.\n\nAssisted-by: Opus 4.7\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/helper/test-pack-deltas.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/helper/test-pack-deltas.c b/t/helper/test-pack-deltas.c\nindex 5e0f726842..959705feca 100644\n--- a/t/helper/test-pack-deltas.c\n+++ b/t/helper/test-pack-deltas.c\n@@ -22,7 +22,7 @@ static unsigned long do_compress(void **pptr, unsigned long size)\n {\n \tgit_zstream stream;\n \tvoid *in, *out;\n-\tunsigned long maxsize;\n+\tsize_t maxsize;\n \n \tgit_deflate_init(&stream, 1);\n \tmaxsize = git_deflate_bound(&stream, size);\n-- \ngitgitgadget\n\n"},{"id":"550537","messageId":"xmqqbjb6t179.fsf@gitster.g","threadId":"65961","inReplyTo":"pull.2175.v3.git.1786632952.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 00/13] Next size_t stop: pack-objects/delta","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-08-13T16:49:46Z","receivedAt":"2026-08-13T16:49:48Z","isPatch":true,"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> This patch series continues the effort to stop using unsigned long where\n> size_t should have been used in the first place. This makes a difference on\n> 64-bit Windows, where unsigned long is 32-bit.\n>\n> With these fixes, the pack-objects machinery works as intended on 64-bit\n> Windows (and any other 64-bit platform where unsigned long isn't 64-bit).\n>\n> Changes since v2:\n>\n>  * Now zlib_cap_buf() is also widened in this patch series (I had left this\n>    for a later one, originally).\n>  * The unpack_object_header_buffer() function is now also widened in this\n>    here patch series.\n\nBoth changes relative to v1 are just as expected.  Nicely corrected.\n\n>   7:  ca928b4579 !  7:  e4528f9034 packfile, git-zlib: widen `use_pack()` and zstream avail fields to `size_t`\n>      @@ builtin/pack-objects.c: size_t oe_get_size_slow(struct packing_data *pack,\n>        \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n>        \t\tsize_t sz;\n>       \n>      + ## git-zlib.c ##\n>      +@@ git-zlib.c: static const char *zerr_to_string(int status)\n>      + \n>      + /* uLong is 32-bit on Windows, even on 64-bit systems */\n>      + #define ULONG_MAX_VALUE maximum_unsigned_value_of_type(uLong)\n>      +-static inline uInt zlib_buf_cap(unsigned long len)\n>      ++static inline uInt zlib_buf_cap(size_t len)\n>      + {\n>      + \treturn (ZLIB_BUF_MAX < len) ? ZLIB_BUF_MAX : len;\n>      + }\n>      +\n>        ## git-zlib.h ##\n>       @@\n>        \n>   -:  ---------- > 13:  bc4a58336a packfile: widen `unpack_object_header_buffer()` to `size_t`\n\n\nIIRC, there are some topics in flight that have their own local\nworkaround for some members this series fixes the type from ulong to\nsize_t and they may need to be adjusted but in a good way ;-).\n\nThanks.  Will replace.\n"}]}