[PATCH v2] read-cache: fix index corruption with index v4
- Date: Thu, 7 Sep 2017 20:24:12 +0100
- From: Thomas Gummerer <t.gummerer@xxxxxxxxx>
- Subject: [PATCH v2] read-cache: fix index corruption with index v4
ce012deb98 ("read-cache: avoid allocating every ondisk entry when
writing", 2017-08-21) changed the way cache entries are written to the
index file. While previously it wrote the name to an struct that was
allocated using xcalloc(), it now uses ce_write() directly. Previously
ce_namelen - common bytes were written to the cache entry, which would
automatically make it nul terminated, as it was allocated using calloc.
Now we are writing ce_namelen - common + 1 bytes directly from the
ce->name to the index. If CE_STRIP_NAME however gets set in the split
index case ce->ce_namelen is set to 0 without changing the actual
ce->name buffer. When index-v4, this results in the first character of
ce->name being written out instead of just a terminating nul charcter.
As index-v4 requires the terminating nul character as terminator of
the name when reading it back, this results in a corrupted index.
Fix that by only writing ce_namelen - common bytes directly from
ce->name to the index, and adding the nul terminator in an extra call to
This bug was turned up by setting TEST_GIT_INDEX_VERSION = 4 in
config.mak and running the test suite (t1700 specifically broke).
Signed-off-by: Thomas Gummerer <t.gummerer@xxxxxxxxx>
> Will send an updated patch in a bit.
In a bit was a lie, I didn't get to it anymore yesterday, but here it is :)
read-cache.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/read-cache.c b/read-cache.c
index 40da87ea71..c6c69cf027 100644
@@ -2103,7 +2103,9 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
result = ce_write(c, fd, to_remove_vi, prefix_size);
- result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common + 1);
+ result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common);
+ if (!result)
+ result = ce_write(c, fd, padding, 1);
strbuf_splice(previous_name, common, to_remove,
ce->name + common, ce_namelen(ce) - common);