Skip to content

Commit dafbe19

Browse files
committed
Merge branch 'ma/split-symref-update-fix'
A leakfix. * ma/split-symref-update-fix: refs/files-backend: add `refname`, not "HEAD", to list refs/files-backend: correct return value in lock_ref_for_update refs/files-backend: fix memory leak in lock_ref_for_update refs/files-backend: add longer-scoped copy of string to list
2 parents 30675f7 + 276d0e3 commit dafbe19

1 file changed

Lines changed: 44 additions & 18 deletions

File tree

refs/files-backend.c

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,11 +2099,10 @@ static int split_head_update(struct ref_update *update,
20992099

21002100
/*
21012101
* First make sure that HEAD is not already in the
2102-
* transaction. This insertion is O(N) in the transaction
2102+
* transaction. This check is O(lg N) in the transaction
21032103
* size, but it happens at most once per transaction.
21042104
*/
2105-
item = string_list_insert(affected_refnames, "HEAD");
2106-
if (item->util) {
2105+
if (string_list_has_string(affected_refnames, "HEAD")) {
21072106
/* An entry already existed */
21082107
strbuf_addf(err,
21092108
"multiple updates for 'HEAD' (including one "
@@ -2118,6 +2117,14 @@ static int split_head_update(struct ref_update *update,
21182117
update->new_oid.hash, update->old_oid.hash,
21192118
update->msg);
21202119

2120+
/*
2121+
* Add "HEAD". This insertion is O(N) in the transaction
2122+
* size, but it happens at most once per transaction.
2123+
* Add new_update->refname instead of a literal "HEAD".
2124+
*/
2125+
if (strcmp(new_update->refname, "HEAD"))
2126+
BUG("%s unexpectedly not 'HEAD'", new_update->refname);
2127+
item = string_list_insert(affected_refnames, new_update->refname);
21212128
item->util = new_update;
21222129

21232130
return 0;
@@ -2144,13 +2151,12 @@ static int split_symref_update(struct files_ref_store *refs,
21442151

21452152
/*
21462153
* First make sure that referent is not already in the
2147-
* transaction. This insertion is O(N) in the transaction
2154+
* transaction. This check is O(lg N) in the transaction
21482155
* size, but it happens at most once per symref in a
21492156
* transaction.
21502157
*/
2151-
item = string_list_insert(affected_refnames, referent);
2152-
if (item->util) {
2153-
/* An entry already existed */
2158+
if (string_list_has_string(affected_refnames, referent)) {
2159+
/* An entry already exists */
21542160
strbuf_addf(err,
21552161
"multiple updates for '%s' (including one "
21562162
"via symref '%s') are not allowed",
@@ -2185,6 +2191,17 @@ static int split_symref_update(struct files_ref_store *refs,
21852191
update->flags |= REF_LOG_ONLY | REF_NODEREF;
21862192
update->flags &= ~REF_HAVE_OLD;
21872193

2194+
/*
2195+
* Add the referent. This insertion is O(N) in the transaction
2196+
* size, but it happens at most once per symref in a
2197+
* transaction. Make sure to add new_update->refname, which will
2198+
* be valid as long as affected_refnames is in use, and NOT
2199+
* referent, which might soon be freed by our caller.
2200+
*/
2201+
item = string_list_insert(affected_refnames, new_update->refname);
2202+
if (item->util)
2203+
BUG("%s unexpectedly found in affected_refnames",
2204+
new_update->refname);
21882205
item->util = new_update;
21892206

21902207
return 0;
@@ -2256,7 +2273,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
22562273
struct strbuf referent = STRBUF_INIT;
22572274
int mustexist = (update->flags & REF_HAVE_OLD) &&
22582275
!is_null_oid(&update->old_oid);
2259-
int ret;
2276+
int ret = 0;
22602277
struct ref_lock *lock;
22612278

22622279
files_assert_main_repository(refs, "lock_ref_for_update");
@@ -2268,7 +2285,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
22682285
ret = split_head_update(update, transaction, head_ref,
22692286
affected_refnames, err);
22702287
if (ret)
2271-
return ret;
2288+
goto out;
22722289
}
22732290

22742291
ret = lock_raw_ref(refs, update->refname, mustexist,
@@ -2282,7 +2299,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
22822299
strbuf_addf(err, "cannot lock ref '%s': %s",
22832300
original_update_refname(update), reason);
22842301
free(reason);
2285-
return ret;
2302+
goto out;
22862303
}
22872304

22882305
update->backend_data = lock;
@@ -2301,10 +2318,12 @@ static int lock_ref_for_update(struct files_ref_store *refs,
23012318
strbuf_addf(err, "cannot lock ref '%s': "
23022319
"error reading reference",
23032320
original_update_refname(update));
2304-
return -1;
2321+
ret = TRANSACTION_GENERIC_ERROR;
2322+
goto out;
23052323
}
23062324
} else if (check_old_oid(update, &lock->old_oid, err)) {
2307-
return TRANSACTION_GENERIC_ERROR;
2325+
ret = TRANSACTION_GENERIC_ERROR;
2326+
goto out;
23082327
}
23092328
} else {
23102329
/*
@@ -2318,13 +2337,15 @@ static int lock_ref_for_update(struct files_ref_store *refs,
23182337
referent.buf, transaction,
23192338
affected_refnames, err);
23202339
if (ret)
2321-
return ret;
2340+
goto out;
23222341
}
23232342
} else {
23242343
struct ref_update *parent_update;
23252344

2326-
if (check_old_oid(update, &lock->old_oid, err))
2327-
return TRANSACTION_GENERIC_ERROR;
2345+
if (check_old_oid(update, &lock->old_oid, err)) {
2346+
ret = TRANSACTION_GENERIC_ERROR;
2347+
goto out;
2348+
}
23282349

23292350
/*
23302351
* If this update is happening indirectly because of a
@@ -2361,7 +2382,8 @@ static int lock_ref_for_update(struct files_ref_store *refs,
23612382
"cannot update ref '%s': %s",
23622383
update->refname, write_err);
23632384
free(write_err);
2364-
return TRANSACTION_GENERIC_ERROR;
2385+
ret = TRANSACTION_GENERIC_ERROR;
2386+
goto out;
23652387
} else {
23662388
update->flags |= REF_NEEDS_COMMIT;
23672389
}
@@ -2375,10 +2397,14 @@ static int lock_ref_for_update(struct files_ref_store *refs,
23752397
if (close_ref(lock)) {
23762398
strbuf_addf(err, "couldn't close '%s.lock'",
23772399
update->refname);
2378-
return TRANSACTION_GENERIC_ERROR;
2400+
ret = TRANSACTION_GENERIC_ERROR;
2401+
goto out;
23792402
}
23802403
}
2381-
return 0;
2404+
2405+
out:
2406+
strbuf_release(&referent);
2407+
return ret;
23822408
}
23832409

23842410
/*

0 commit comments

Comments
 (0)