odb_pack: fix race condition last_found is the last packfile a wanted object was found in. Since last_found is shared among all searching threads, it might changes while we're searching. As suggested by @arrbee, put a copy on the stack to fix the race condition.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
diff --git a/src/odb_pack.c b/src/odb_pack.c
index d33d064..b4f958b 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -267,9 +267,10 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
{
int error;
unsigned int i;
+ struct git_pack_file *last_found = backend->last_found;
- if (backend->last_found &&
- git_pack_entry_find(e, backend->last_found, oid, GIT_OID_HEXSZ) == 0)
+ if (last_found &&
+ git_pack_entry_find(e, last_found, oid, GIT_OID_HEXSZ) == 0)
return 0;
if ((error = packfile_refresh_all(backend)) < 0)
@@ -279,7 +280,7 @@ static int pack_entry_find(struct git_pack_entry *e, struct pack_backend *backen
struct git_pack_file *p;
p = git_vector_get(&backend->packs, i);
- if (p == backend->last_found)
+ if (p == last_found)
continue;
if (git_pack_entry_find(e, p, oid, GIT_OID_HEXSZ) == 0) {
@@ -300,12 +301,13 @@ static int pack_entry_find_prefix(
int error;
unsigned int i;
unsigned found = 0;
+ struct git_pack_file *last_found = backend->last_found;
if ((error = packfile_refresh_all(backend)) < 0)
return error;
- if (backend->last_found) {
- error = git_pack_entry_find(e, backend->last_found, short_oid, len);
+ if (last_found) {
+ error = git_pack_entry_find(e, last_found, short_oid, len);
if (error == GIT_EAMBIGUOUS)
return error;
if (!error)
@@ -316,7 +318,7 @@ static int pack_entry_find_prefix(
struct git_pack_file *p;
p = git_vector_get(&backend->packs, i);
- if (p == backend->last_found)
+ if (p == last_found)
continue;
error = git_pack_entry_find(e, p, short_oid, len);