{"thread":{"id":"66726","subject":"[PATCH 0/4] use size_t when parsing and checking objects","startedAt":"2026-10-31T11:09:56Z","lastAt":"2026-10-31T18:37:17Z","messageCount":7,"participants":["Elia Pinto","Simon Richter"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"557010","messageId":"cover.1793444420.git.gitter.spiros@gmail.com","threadId":"66726","inReplyTo":null,"subject":"[PATCH 0/4] use size_t when parsing and checking objects","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T11:09:56Z","receivedAt":"2026-10-31T11:09:56Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"This series continues the search for truncated sizes on platforms where\n\"long\" is 32 bits (Windows). It covers the functions that parse, verify,\nand check whole objects in memory: they take the size as an \"unsigned\nlong\", while their callers have a size_t, so above 4GiB the size gets\ntruncated.\n\nEach patch addresses a specific component:\n - 1/4: a valid object reported as corrupt;\n - 2/4: fsck looks at only a prefix (e.g., .gitmodules);\n - 3/4: parsing of a prefix (with set_commit_buffer() now dying instead\n   of caching a truncated size, as repo_get_commit_buffer() already\n   does);\n - 4/4: \"git tag -v\" doesn't find the signature, plus the int index in\n   copy_subject() on all platforms.\n\nThere are no out-of-bounds accesses; large objects only fail or are\nhandled as if they were shorter.\n\nNo tests are added because they would need objects over 4GiB in memory,\nand they'd only detect the bug where long is 32 bits. I am happy to add\nEXPENSIVE tests guarded by !LONG_IS_64BIT (like t1051) if reviewers\nprefer.\n\nNot covered here: the pack paths (index-pack, unpack-objects, pack\nverification) still pass an \"unsigned long\" to fsck_object(); that's the\nnext series. The tree API (parse_tree_buffer(), init_tree_desc*()) is in\nthe tree-walk series:\n  https://lore.kernel.org/git/cover.1793357680.git.gitter.spiros@gmail.com/\nThis series doesn't depend on the other series in flight and merges\ncleanly with them. Based on master 50fe5cc63f.\n\nElia Pinto (4):\n  object-file: use size_t in check_object_signature()\n  fsck: use size_t for the size of objects to check\n  object, commit, tag: use size_t when parsing object buffers\n  tag, fmt-merge-msg, ref-filter: use size_t for message buffers\n\n commit.c              |  8 ++++----\n commit.h              |  6 +++---\n fmt-merge-msg.c       |  2 +-\n fsck.c                | 18 +++++++++---------\n fsck.h                |  6 +++---\n object-file-convert.c |  2 +-\n object-file.c         |  2 +-\n object-file.h         |  2 +-\n object.c              |  2 +-\n object.h              |  2 +-\n ref-filter.c          |  6 +++---\n tag.c                 |  4 ++--\n tag.h                 |  2 +-\n 13 files changed, 31 insertions(+), 31 deletions(-)\n\n\nbase-commit: 50fe5cc63f9cd6e89b87a2c9ccf96a444f4cfdb7\n-- \n2.53.0\n\n\n"},{"id":"557011","messageId":"1f1d1dab569f2d8ad3087d8c877a87747e0b0c6a.1793444420.git.gitter.spiros@gmail.com","threadId":"66726","inReplyTo":"cover.1793444420.git.gitter.spiros@gmail.com","subject":"[PATCH 1/4] object-file: use size_t in check_object_signature()","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T11:09:57Z","receivedAt":"2026-10-31T11:09:57Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"check_object_signature() takes the object size as an \"unsigned long\",\nwhile its callers pass a size_t from odb_read_object(), and the internal\nfunction it calls, hash_object_file(), already accepts a size_t. So the\nsize is narrowed only here, and specifically on Windows where \"long\"\nis 32 bits wide.\n\nOn platforms with 32-bit longs, hashing an object of 4GiB or more\ntruncates the size, causing it to hash only a prefix. This mismatch\nresults in valid objects being incorrectly flagged as corrupt by\ncallers like parse_object() or git fsck.\n\nUse size_t for the size parameter, matching what callers\nalready provide.\n\nTriggering this requires processing 4GiB or more of input on a platform\nwhere \"long\" is 32 bits, so no test is added.\n\nSigned-off-by: Elia Pinto <gitter.spiros@gmail.com>\n---\n object-file.c | 2 +-\n object-file.h | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/object-file.c b/object-file.c\nindex c049bf13f7..3cb8f3fac1 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -111,7 +111,7 @@ int format_object_header(char *str, size_t size, enum object_type type,\n }\n \n int check_object_signature(struct repository *r, const struct object_id *oid,\n-\t\t\t   void *buf, unsigned long size,\n+\t\t\t   void *buf, size_t size,\n \t\t\t   enum object_type type)\n {\n \tconst struct git_hash_algo *algo =\ndiff --git a/object-file.h b/object-file.h\nindex f44758c4f8..53c0e6df09 100644\n--- a/object-file.h\n+++ b/object-file.h\n@@ -92,7 +92,7 @@ int format_object_header(char *str, size_t size, enum object_type type,\n  * what we expected, but it might also indicate another error.\n  */\n int check_object_signature(struct repository *r, const struct object_id *oid,\n-\t\t\t   void *map, unsigned long size,\n+\t\t\t   void *map, size_t size,\n \t\t\t   enum object_type type);\n \n /**\n-- \n2.53.0\n\n\n"},{"id":"557012","messageId":"7551e796e7d27fbe3a6710801adce788bdc17230.1793444420.git.gitter.spiros@gmail.com","threadId":"66726","inReplyTo":"cover.1793444420.git.gitter.spiros@gmail.com","subject":"[PATCH 2/4] fsck: use size_t for the size of objects to check","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T11:09:58Z","receivedAt":"2026-10-31T11:09:58Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"fsck functions such as fsck_object() and fsck_buffer() take the object\nsize as an \"unsigned long\", while some callers pass a size_t. On\nplatforms where \"long\" is 32 bits, this truncates the size for objects\nof 4GiB or more.\n\nWhen checking large objects on those platforms, fsck inspects only a\nprefix of the buffer.\n\nUse size_t for the size parameter across the fsck functions and internal\nhelpers, including the loop index in verify_headers().\n\nSome callers and pack verification paths still pass \"unsigned long\" to\nfsck_object(), and fsck_tree() passes the size to tree-walk routines;\nthose will be updated separately.\n\nTriggering this requires processing 4GiB or more of input on a platform\nwhere \"long\" is 32 bits, so no test is added.\n\nSigned-off-by: Elia Pinto <gitter.spiros@gmail.com>\n---\n fsck.c | 18 +++++++++---------\n fsck.h |  6 +++---\n 2 files changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex 94c8651c7d..7b0e9a5892 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -614,7 +614,7 @@ static int verify_ordered(unsigned mode1, const char *name1,\n }\n \n static int fsck_tree(const struct object_id *tree_oid,\n-\t\t     const char *buffer, unsigned long size,\n+\t\t     const char *buffer, size_t size,\n \t\t     struct fsck_options *options)\n {\n \tint retval = 0;\n@@ -826,12 +826,12 @@ static int fsck_tree(const struct object_id *tree_oid,\n  *     case hit the newline we found here as the end-of-header. This makes it\n  *     OK for them to use helpers like parse_oid_hex(), or even skip_prefix().\n  */\n-static int verify_headers(const void *data, unsigned long size,\n+static int verify_headers(const void *data, size_t size,\n \t\t\t  const struct object_id *oid, enum object_type type,\n \t\t\t  struct fsck_options *options)\n {\n \tconst char *buffer = (const char *)data;\n-\tunsigned long i;\n+\tsize_t i;\n \n \tfor (i = 0; i < size; i++) {\n \t\tswitch (buffer[i]) {\n@@ -948,7 +948,7 @@ static int fsck_ident(const char **ident, const char *ident_end,\n }\n \n static int fsck_commit(const struct object_id *oid,\n-\t\t       const char *buffer, unsigned long size,\n+\t\t       const char *buffer, size_t size,\n \t\t       struct fsck_options *options)\n {\n \tstruct object_id tree_oid, parent_oid;\n@@ -1010,7 +1010,7 @@ static int fsck_commit(const struct object_id *oid,\n }\n \n static int fsck_tag(const struct object_id *oid, const char *buffer,\n-\t\t    unsigned long size, struct fsck_options *options)\n+\t\t    size_t size, struct fsck_options *options)\n {\n \tstruct object_id tagged_oid;\n \tint tagged_type;\n@@ -1019,7 +1019,7 @@ static int fsck_tag(const struct object_id *oid, const char *buffer,\n }\n \n int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n-\t\t\tunsigned long size, struct fsck_options *options,\n+\t\t\tsize_t size, struct fsck_options *options,\n \t\t\tstruct object_id *tagged_oid,\n \t\t\tint *tagged_type)\n {\n@@ -1182,7 +1182,7 @@ static int fsck_gitmodules_fn(const char *var, const char *value,\n }\n \n static int fsck_blob(const struct object_id *oid, const char *buf,\n-\t\t     unsigned long size, struct fsck_options *options)\n+\t\t     size_t size, struct fsck_options *options)\n {\n \tint ret = 0;\n \n@@ -1251,7 +1251,7 @@ static int fsck_blob(const struct object_id *oid, const char *buf,\n \treturn ret;\n }\n \n-int fsck_object(struct object *obj, void *data, unsigned long size,\n+int fsck_object(struct object *obj, void *data, size_t size,\n \tstruct fsck_options *options)\n {\n \tif (!obj)\n@@ -1261,7 +1261,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size,\n }\n \n int fsck_buffer(const struct object_id *oid, enum object_type type,\n-\t\tconst void *data, unsigned long size,\n+\t\tconst void *data, size_t size,\n \t\tstruct fsck_options *options)\n {\n \tif (type == OBJ_BLOB)\ndiff --git a/fsck.h b/fsck.h\nindex e77935c8a9..2a075a5572 100644\n--- a/fsck.h\n+++ b/fsck.h\n@@ -196,7 +196,7 @@ int fsck_walk(struct object *obj, void *data, struct fsck_options *options);\n  * Blob objects my pass a NULL data pointer, which indicates they are too large\n  * to fit in memory. All other types must pass a real buffer.\n  */\n-int fsck_object(struct object *obj, void *data, unsigned long size,\n+int fsck_object(struct object *obj, void *data, size_t size,\n \tstruct fsck_options *options);\n \n /*\n@@ -204,7 +204,7 @@ int fsck_object(struct object *obj, void *data, unsigned long size,\n  * struct.\n  */\n int fsck_buffer(const struct object_id *oid, enum object_type,\n-\t\tconst void *data, unsigned long size,\n+\t\tconst void *data, size_t size,\n \t\tstruct fsck_options *options);\n \n /*\n@@ -212,7 +212,7 @@ int fsck_buffer(const struct object_id *oid, enum object_type,\n  * exposed fsck_object() internals for git-mktag(1).\n  */\n int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n-\t\t\tunsigned long size, struct fsck_options *options,\n+\t\t\tsize_t size, struct fsck_options *options,\n \t\t\tstruct object_id *tagged_oid,\n \t\t\tint *tag_type);\n \n-- \n2.53.0\n\n\n"},{"id":"557013","messageId":"745c6d04d33dd118a1c8185d0b851d79d171ab98.1793444420.git.gitter.spiros@gmail.com","threadId":"66726","inReplyTo":"cover.1793444420.git.gitter.spiros@gmail.com","subject":"[PATCH 3/4] object, commit, tag: use size_t when parsing object buffers","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T11:09:59Z","receivedAt":"2026-10-31T11:09:59Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"Functions like parse_object_buffer(), parse_commit_buffer(),\nparse_tag_buffer(), and decode_tree_entry_raw() take the buffer size as\nan \"unsigned long\", while callers pass a size_t. On platforms where\n\"long\" is 32 bits, this truncates the size for objects of 4GiB or more.\n\nWhen parsing large objects on those platforms, only a prefix of the\nbuffer is parsed. For example, a signature placed at the end of a large\ntag can be missed.\n\nUse size_t for the size parameter across these parsing functions. For\nset_commit_buffer(), the commit cache slab still stores \"unsigned long\"\nsizes due to accessors like repo_get_commit_buffer() handing out the\nsize through an \"unsigned long *\" output parameter. Therefore,\nset_commit_buffer() narrows the size with cast_size_t_to_ulong(), dying\non objects of 4GiB or more on 32-bit long platforms instead of caching a\ntruncated size, mirroring the behavior already implemented in\nrepo_get_commit_buffer().\n\nparse_tree_buffer() is changed separately.\n\nTriggering this requires processing 4GiB or more of input on a platform\nwhere \"long\" is 32 bits, so no test is added.\n\nSigned-off-by: Elia Pinto <gitter.spiros@gmail.com>\n---\n commit.c              | 8 ++++----\n commit.h              | 6 +++---\n object-file-convert.c | 2 +-\n object.c              | 2 +-\n object.h              | 2 +-\n tag.c                 | 2 +-\n tag.h                 | 2 +-\n 7 files changed, 12 insertions(+), 12 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex ad26f0b40a..a94acf4e6f 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -366,12 +366,12 @@ void free_commit_buffer_slab(struct buffer_slab *bs)\n \tfree(bs);\n }\n \n-void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size)\n+void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, size_t size)\n {\n \tstruct commit_buffer *v = buffer_slab_at(\n \t\tr->parsed_objects->buffer_slab, commit);\n \tv->buffer = buffer;\n-\tv->size = size;\n+\tv->size = cast_size_t_to_ulong(size);\n }\n \n const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep)\n@@ -513,7 +513,7 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)\n \treturn ret;\n }\n \n-int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph)\n+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph)\n {\n \tconst char *tail = buffer;\n \tconst char *bufptr = buffer;\n@@ -1195,7 +1195,7 @@ int parse_signed_commit(const struct commit *commit,\n }\n \n int parse_buffer_signed_by_header(const char *buffer,\n-\t\t\t\t  unsigned long size,\n+\t\t\t\t  size_t size,\n \t\t\t\t  struct strbuf *payload,\n \t\t\t\t  struct strbuf *signature,\n \t\t\t\t  const struct git_hash_algo *algop)\ndiff --git a/commit.h b/commit.h\nindex 1061ed791b..6a6ff25e12 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -92,7 +92,7 @@ struct commit *lookup_commit_reference_by_name_gently(const char *name,\n  */\n struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);\n \n-int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph);\n+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, size_t size, int check_graph);\n int repo_parse_commit_internal(struct repository *r, struct commit *item,\n \t\t\t       int quiet_on_missing, int use_commit_graph);\n int repo_parse_commit_gently(struct repository *r,\n@@ -131,7 +131,7 @@ void free_commit_buffer_slab(struct buffer_slab *bs);\n  * Associate an object buffer with the commit. The ownership of the\n  * memory is handed over to the commit, and must be free()-able.\n  */\n-void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size);\n+void set_commit_buffer(struct repository *r, struct commit *, void *buffer, size_t size);\n \n /*\n  * Get any cached object buffer associated with the commit. Returns NULL\n@@ -381,7 +381,7 @@ int run_commit_hook(int editor_is_used, const char *index_file,\n \n /* Parse the signature out of a header. */\n int parse_buffer_signed_by_header(const char *buffer,\n-\t\t\t\t  unsigned long size,\n+\t\t\t\t  size_t size,\n \t\t\t\t  struct strbuf *payload,\n \t\t\t\t  struct strbuf *signature,\n \t\t\t\t  const struct git_hash_algo *algop);\ndiff --git a/object-file-convert.c b/object-file-convert.c\nindex 63ee18630b..ead88c1021 100644\n--- a/object-file-convert.c\n+++ b/object-file-convert.c\n@@ -51,7 +51,7 @@ int repo_oid_to_algop(struct repository *repo, const struct object_id *srcoid,\n \n static int decode_tree_entry_raw(struct object_id *oid, const char **path,\n \t\t\t\t size_t *len, const struct git_hash_algo *algo,\n-\t\t\t\t const char *buf, unsigned long size)\n+\t\t\t\t const char *buf, size_t size)\n {\n \tuint16_t mode;\n \tconst unsigned hashsz = algo->rawsz;\ndiff --git a/object.c b/object.c\nindex 97f7fc0e87..541ac90dc6 100644\n--- a/object.c\n+++ b/object.c\n@@ -258,7 +258,7 @@ enum peel_status peel_object(struct repository *r,\n \treturn peel_object_ext(r, name, oid, flags, &dummy);\n }\n \n-struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)\n+struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p)\n {\n \tstruct object *obj;\n \t*eaten_p = 0;\ndiff --git a/object.h b/object.h\nindex 46cade33fb..9bf23321a7 100644\n--- a/object.h\n+++ b/object.h\n@@ -241,7 +241,7 @@ struct object *parse_object_or_die(struct repository *repo, const struct object_\n  * parsing it.  eaten_p indicates if the object has a borrowed copy\n  * of buffer and the caller should not free() it.\n  */\n-struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p);\n+struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, size_t size, void *buffer, int *eaten_p);\n \n /*\n  * Allocate and return an object struct, even if you do not know the type of\ndiff --git a/tag.c b/tag.c\nindex 1a00ded6eb..414681c64f 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -127,7 +127,7 @@ void release_tag_memory(struct tag *t)\n \tt->date = 0;\n }\n \n-int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size)\n+int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size)\n {\n \tstruct object_id oid;\n \tchar type[20];\ndiff --git a/tag.h b/tag.h\nindex 534687c4ca..a5f0f06c82 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -12,7 +12,7 @@ struct tag {\n \ttimestamp_t date;\n };\n struct tag *lookup_tag(struct repository *r, const struct object_id *oid);\n-int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size);\n+int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, size_t size);\n int parse_tag(struct repository *r, struct tag *item);\n void release_tag_memory(struct tag *t);\n struct object *deref_tag(struct repository *r, struct object *, const char *, int);\n-- \n2.53.0\n\n\n"},{"id":"557014","messageId":"7008380756525a72d292a473613a7b3d9dd5d8d4.1793444420.git.gitter.spiros@gmail.com","threadId":"66726","inReplyTo":"cover.1793444420.git.gitter.spiros@gmail.com","subject":"[PATCH 4/4] tag, fmt-merge-msg, ref-filter: use size_t for message buffers","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T11:10:00Z","receivedAt":"2026-10-31T11:10:00Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"Functions like run_gpg_verify(), fmt_tag_signature(), copy_subject(),\nand append_lines() take the length of a tag or message as an \"unsigned\nlong\", while callers pass a size_t. On platforms where \"long\" is 32\nbits, this truncates the length for objects of 4GiB or more.\n\nWhen handling large tags or messages on those platforms, \"git tag -v\"\ninspects only a prefix and fails to find the signature placed at the end\nof the tag. Additionally, in copy_subject(), the loop index is an \"int\",\ncausing an overflow on subjects of 2GiB or more across all platforms.\n\nUse size_t for the length parameters and the loop index.\n\nTriggering this requires processing 2GiB or 4GiB or more of input, so no\ntest is added.\n\nSigned-off-by: Elia Pinto <gitter.spiros@gmail.com>\n---\n fmt-merge-msg.c | 2 +-\n ref-filter.c    | 6 +++---\n tag.c           | 2 +-\n 3 files changed, 5 insertions(+), 5 deletions(-)\n\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 14441f23ae..5a96c50383 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -505,7 +505,7 @@ static void fmt_merge_msg_title(struct strbuf *out,\n static void fmt_tag_signature(struct strbuf *tagbuf,\n \t\t\t      struct strbuf *sig,\n \t\t\t      const char *buf,\n-\t\t\t      unsigned long len)\n+\t\t\t      size_t len)\n {\n \tconst char *tag_body = strstr(buf, \"\\n\\n\");\n \tif (tag_body) {\ndiff --git a/ref-filter.c b/ref-filter.c\nindex bdf54f6f59..8e2dcb74b0 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1657,10 +1657,10 @@ static const char *copy_email(const char *buf, struct used_atom *atom)\n \treturn xmemdupz(email, eoemail - email);\n }\n \n-static char *copy_subject(const char *buf, unsigned long len)\n+static char *copy_subject(const char *buf, size_t len)\n {\n \tstruct strbuf sb = STRBUF_INIT;\n-\tint i;\n+\tsize_t i;\n \n \tfor (i = 0; i < len; i++) {\n \t\tif (buf[i] == '\\r' && i + 1 < len && buf[i + 1] == '\\n')\n@@ -1952,7 +1952,7 @@ static void find_subpos(const char *buf,\n  * If 'lines' is greater than 0, append that many lines from the given\n  * 'buf' of length 'size' to the given strbuf.\n  */\n-static void append_lines(struct strbuf *out, const char *buf, unsigned long size, int lines)\n+static void append_lines(struct strbuf *out, const char *buf, size_t size, int lines)\n {\n \tint i;\n \tconst char *sp, *eol;\ndiff --git a/tag.c b/tag.c\nindex 414681c64f..8709e8c46d 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -16,7 +16,7 @@\n \n const char *tag_type = \"tag\";\n \n-static int run_gpg_verify(const char *buf, unsigned long size, unsigned flags)\n+static int run_gpg_verify(const char *buf, size_t size, unsigned flags)\n {\n \tstruct signature_check sigc;\n \tstruct strbuf payload = STRBUF_INIT;\n-- \n2.53.0\n\n\n"},{"id":"557034","messageId":"b6c3c811-cabf-4421-aab2-f6b4b30951c2@hogyros.de","threadId":"66726","inReplyTo":"cover.1793444420.git.gitter.spiros@gmail.com","subject":"Re: [PATCH 0/4] use size_t when parsing and checking objects","fromName":"Simon Richter","fromEmail":"simon.richter@hogyros.de","sentAt":"2026-10-31T17:06:09Z","receivedAt":"2026-10-31T17:06:09Z","isPatch":true,"sender":{"key":"simon.richter@hogyros.de","avatar":"https://gravatar.com/avatar/1192aa9fa5dd19ce258b12b044cc27111dd7cdb58d920dc2123a02a24f55b5c5?d=mp&s=160"},"body":"Hi,\n\nOn 10/31/26 20:09, Elia Pinto wrote:\n\n> This series continues the search for truncated sizes on platforms where\n> \"long\" is 32 bits (Windows). It covers the functions that parse, verify,\n> and check whole objects in memory: they take the size as an \"unsigned\n> long\", while their callers have a size_t, so above 4GiB the size gets\n> truncated.\nAgain, reminder that size_t is also 32 bit on 32-bit architectures, because size_t is used for the size of in-memory objects.\n\nAnything that is on disk can have a size that only fits into an off_t, which is 64 bit if large file support is enabled, and 32 bit if it is not. If large file support is disabled, opening a file larger than 2 GB is supposed to fail (because you need to pass O_LARGEFILE, which is defined only if large file support is enabled), but there is a chance that an on-disk object got truncated, so that is not guaranteed.\n\nSo, use size_t only for in-memory data, but if you are reading data from disk piecewise, the total count of data processed needs to be an off_t.\n\n   Simon\n"},{"id":"557040","messageId":"20261031183717.273904-1-gitter.spiros@gmail.com","threadId":"66726","inReplyTo":"b6c3c811-cabf-4421-aab2-f6b4b30951c2@hogyros.de","subject":"Re: [PATCH 0/4] use size_t when parsing and checking objects","fromName":"Elia Pinto","fromEmail":"gitter.spiros@gmail.com","sentAt":"2026-10-31T18:37:17Z","receivedAt":"2026-10-31T18:37:17Z","isPatch":true,"sender":{"key":"gitter.spiros@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158490?v=4"},"body":"On Sun, Nov 01, 2026 at 02:06:09AM +0900, Simon Richter wrote:\n> > This series continues the search for truncated sizes on platforms where\n> > \"long\" is 32 bits (Windows). It covers the functions that parse, verify,\n> > and check whole objects in memory: they take the size as an \"unsigned\n> > long\", while their callers have a size_t, so above 4GiB the size gets\n> > truncated.\n> Again, reminder that size_t is also 32 bit on 32-bit architectures, \n> because size_t is used for the size of in-memory objects.\n\nAgreed. On a 32-bit system, objects over 4GiB cannot be held in memory\nanyway. The mention of Windows in the cover letter refers to LLP64,\nwhere size_t is 64 bits but long is 32 bits, which is precisely the case\nthis series fixes.\n\n>\n> Anything that is on disk can have a size that only fits into an off_t, \n> which is 64 bit if large file support is enabled, and 32 bit if it is \n> not. If large file support is disabled, opening a file larger than 2 GB \n> is supposed to fail (because you need to pass O_LARGEFILE, which is \n> defined only if large file support is enabled), but there is a chance \n> that an on-disk object got truncated, so that is not guaranteed.\n\n>\n> So, use size_t only for in-memory data, but if you are reading data from \n> disk piecewise, the total count of data processed needs to be an off_t.\n\nIndeed. This series only deals with buffers already entirely in memory\n(in check_object_signature(), fsck, parse_*_buffer(), and the message\nhelpers), where size_t is the appropriate type.\n\nYour remark prompted me to take another look at the other patches. In\npack-objects, the accumulated length that write_large_blob_data() tracks\nwhile writing the stream piece by piece was indeed a size_t. That fits\nyour point precisely, so v2 of that patch, which I am sending as a\nreply to v1, uses off_t:\n\n  https://lore.kernel.org/git/20261031180411.257932-1-gitter.spiros@gmail.com/\n\nThanks for the insightful review!\n\nElia\n\n"}]}