git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 1/3] odb: use size_t for the length of objects to write

From
Elia Pinto <gitter.spiros@gmail.com>
Date
Oct 21, 2026, 10:16 UTC
Message-ID
<20261021101640.329990-2-gitter.spiros@gmail.com>
In-Reply-To
<20261021101640.329990-1-gitter.spiros@gmail.com>

c6a4629e32 (odb: use size_t for object_info.sizep and the size APIs, 2026-06-15) widened the read side of the object database API, and the write_object() callback of odb_source already takes a size_t. But odb_write_object_ext(), odb_write_object() and odb_source_write_object() in front of it, as well as write_loose_object() behind it, still take an "unsigned long", which is only 32 bits wide on Windows.

Most callers hand them a size_t from a strbuf or from odb_read_object(), which silently gets truncated. The most visible case is index_mem() and index_stream_convert_blob(): when "git add" or "git hash-object -w" runs a file over 4GiB through a conversion (core.autocrlf, which is on by default in Git for Windows, an eol or ident attribute, or a clean filter), we write a blob made of the first "size mod 2^32" bytes. The index records it with the stat data of the real file, so "git status" stays clean and nobody notices until the file is checked out again. "git hash-object" without "-w" uses hash_object_file(), which takes a size_t, so the two disagree on the object ID of the same file.

Use size_t throughout, including for the size kept by the in-memory source.

The existing "hash filtered files over 4GB correctly" test in t1007 only hashes. Running the same with "git hash-object -w" on Windows shows the problem, but needs another pass over a 5GiB file, so no new test is added here.

Signed-off-by: Elia Pinto <gitter.spiros@gmail.com>
---
 odb.c                 | 2 +-
 odb.h                 | 4 ++--
 odb/source-inmemory.c | 2 +-
 odb/source-loose.c    | 2 +-
 odb/source.h          | 2 +-
 5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/odb.c b/odb.c
index 98c5c862f5..6e9daf11e4 100644
--- a/odb.c
+++ b/odb.c
@@ -667,7 +667,7 @@ void odb_assert_oid_type(struct object_database *odb,
 }
 
 int odb_write_object_ext(struct object_database *odb,
-			 const void *buf, unsigned long len,
+			 const void *buf, size_t len,
 			 enum object_type type,
 			 struct object_id *oid,
 			 const struct object_id *compat_oid_in,
diff --git a/odb.h b/odb.h
index 0ccc47ee73..25d02fae75 100644
--- a/odb.h
+++ b/odb.h
@@ -633,14 +633,14 @@ enum odb_write_object_flags {
  * Returns 0 on success, a negative error code otherwise.
  */
 int odb_write_object_ext(struct object_database *odb,
-			 const void *buf, unsigned long len,
+			 const void *buf, size_t len,
 			 enum object_type type,
 			 struct object_id *oid,
 			 const struct object_id *compat_oid,
 			 enum odb_write_object_flags flags);
 
 static inline int odb_write_object(struct object_database *odb,
-				   const void *buf, unsigned long len,
+				   const void *buf, size_t len,
 				   enum object_type type,
 				   struct object_id *oid)
 {
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index 868e723c81..ab7173cd2d 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -10,7 +10,7 @@
 struct inmemory_object {
 	enum object_type type;
 	const void *buf;
-	unsigned long size;
+	size_t size;
 };
 
 static const struct inmemory_object *find_cached_object(struct odb_source_inmemory *source,
diff --git a/odb/source-loose.c b/odb/source-loose.c
index 0664634938..fe1a298364 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -770,7 +770,7 @@ static int end_loose_object_common(struct odb_source_loose *loose,
 
 static int write_loose_object(struct odb_source_loose *loose,
 			      const struct object_id *oid, char *hdr,
-			      int hdrlen, const void *buf, unsigned long len,
+			      int hdrlen, const void *buf, size_t len,
 			      const time_t *mtime, unsigned flags)
 {
 	int fd, ret;
diff --git a/odb/source.h b/odb/source.h
index 1867347dfc..8e6ed96399 100644
--- a/odb/source.h
+++ b/odb/source.h
@@ -469,7 +469,7 @@ static inline int odb_source_freshen_object(struct odb_source *source,
  * object ID and the compatibility object ID, if non-NULL.
  */
 static inline int odb_source_write_object(struct odb_source *source,
-					  const void *buf, unsigned long len,
+					  const void *buf, size_t len,
 					  enum object_type type,
 					  const struct object_id *oid,
 					  const struct object_id *compat_oid,
-- 
2.53.0
Previous: Elia PintoNext: Patrick Steinhardt
Message 2 of 21 in “use size_t for a few more object and buffer sizes”
  1. 0/3 use size_t for a few more object and buffer sizesElia Pinto, Oct 21, 2026
  2. 1/3 odb: use size_t for the length of objects to writeElia Pinto, Oct 21, 2026
  3. Patrick SteinhardtOct 21, 2026
  4. 2/3 diff: use size_t for the allocation size of word-diff buffersElia Pinto, Oct 21, 2026
  5. Patrick SteinhardtOct 21, 2026
  6. 3/3 convert: use size_t for buffer sizesElia Pinto, Oct 21, 2026
  7. Patrick SteinhardtOct 21, 2026
  8. 0/4 use size_t for a few more object and buffer sizesElia Pinto, Oct 30, 2026
  9. 1/4 odb: use size_t for the length of objects to writeElia Pinto, Oct 30, 2026
  10. Patrick SteinhardtOct 30, 2026
  11. Elia PintoOct 31, 2026
  12. 2/4 diff: use size_t for the allocation size of word-diff buffersElia Pinto, Oct 30, 2026
  13. 3/4 convert: use size_t for buffer sizesElia Pinto, Oct 30, 2026
  14. 4/4 convert: use size_t for text statistics and ident countsElia Pinto, Oct 30, 2026
  15. Patrick SteinhardtOct 30, 2026
  16. Elia PintoOct 31, 2026
  17. 0/4 use size_t for a few more object and buffer sizesElia Pinto, Oct 31, 2026
  18. 1/4 odb: use size_t for the length of objects to writeElia Pinto, Oct 31, 2026
  19. 2/4 diff: use size_t for the allocation size of word-diff buffersElia Pinto, Oct 31, 2026
  20. 3/4 convert: use size_t for buffer sizesElia Pinto, Oct 31, 2026
  21. 4/4 convert: use size_t for text statistics and ident countsElia Pinto, Oct 31, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.