diff options
author | lhchavez <lhchavez@lhchavez.com> | 2017-12-23 14:59:07 +0000 |
---|---|---|
committer | lhchavez <lhchavez@lhchavez.com> | 2017-12-23 14:59:07 +0000 |
commit | c3514b0b82e90e660c996e81a525d42c025503ab (patch) | |
tree | c4fe81c1f539c23d7a95ac607a551cb11fec865d /src/indexer.c | |
parent | 9f7ad3c5d34d35a5ec2f34fa9cd8c92eff439329 (diff) | |
download | libgit2-c3514b0b82e90e660c996e81a525d42c025503ab.tar.gz |
Fix unpack double free
If an element has been cached, but then the call to
packfile_unpack_compressed() fails, the very next thing that happens is
that its data is freed and then the element is not removed from the
cache, which frees the data again.
This change sets obj->data to NULL to avoid the double-free. It also
stops trying to resolve deltas after two continuous failed rounds of
resolution, and adds a test for this.
Diffstat (limited to 'src/indexer.c')
-rw-r--r-- | src/indexer.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/src/indexer.c b/src/indexer.c index 7eec0d612..a5e842272 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -844,6 +844,7 @@ static int fix_thin_pack(git_indexer *idx, git_transfer_progress *stats) static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats) { unsigned int i; + int error; struct delta_info *delta; int progressed = 0, non_null = 0, progress_cb_result; @@ -858,8 +859,13 @@ static int resolve_deltas(git_indexer *idx, git_transfer_progress *stats) non_null = 1; idx->off = delta->delta_off; - if (git_packfile_unpack(&obj, idx->pack, &idx->off) < 0) - continue; + if ((error = git_packfile_unpack(&obj, idx->pack, &idx->off)) < 0) { + if (error == GIT_PASSTHROUGH) { + /* We have not seen the base object, we'll try again later. */ + continue; + } + return -1; + } if (hash_and_save(idx, &obj, delta->delta_off) < 0) continue; |