Skip to content

Commit c299468

Browse files
Martin Ågrengitster
authored andcommitted
refs/files-backend: add longer-scoped copy of string to list
split_symref_update() receives a string-pointer `referent` and adds it to the list of `affected_refnames`. The list simply holds on to the pointers it is given, it does not copy the strings and it does not ever free them. The `referent` string in split_symref_update() belongs to a string buffer in the caller. After we return, the string will be leaked. In the next patch, we want to properly release the string buffer in the caller, but we can't safely do so until we've made sure that `affected_refnames` will not be holding on to a pointer to the string. We could configure the list to handle its own resources, but it would mean some alloc/free-churning. The list is already handling other strings (through other code paths) which we do not need to worry about, and we'd be memory-churning those strings too, completely unnecessary. Observe that split_symref_update() creates a `new_update`-object through ref_transaction_add_update(), after which `new_update->refname` is a copy of `referent`. The difference is, this copy will be freed, and it will be freed *after* `affected_refnames` has been cleared. Rearrange the handling of `referent`, so that we don't add it directly to `affected_refnames`. Instead, first just check whether `referent` exists in the string list, and later add `new_update->refname`. Helped-by: Michael Haggerty <mhagger@alum.mit.edu> Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Martin Ågren <martin.agren@gmail.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 4384e3c commit c299468

1 file changed

Lines changed: 14 additions & 4 deletions

File tree

refs/files-backend.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,13 +2634,12 @@ static int split_symref_update(struct files_ref_store *refs,
26342634

26352635
/*
26362636
* First make sure that referent is not already in the
2637-
* transaction. This insertion is O(N) in the transaction
2637+
* transaction. This check is O(lg N) in the transaction
26382638
* size, but it happens at most once per symref in a
26392639
* transaction.
26402640
*/
2641-
item = string_list_insert(affected_refnames, referent);
2642-
if (item->util) {
2643-
/* An entry already existed */
2641+
if (string_list_has_string(affected_refnames, referent)) {
2642+
/* An entry already exists */
26442643
strbuf_addf(err,
26452644
"multiple updates for '%s' (including one "
26462645
"via symref '%s') are not allowed",
@@ -2675,6 +2674,17 @@ static int split_symref_update(struct files_ref_store *refs,
26752674
update->flags |= REF_LOG_ONLY | REF_NODEREF;
26762675
update->flags &= ~REF_HAVE_OLD;
26772676

2677+
/*
2678+
* Add the referent. This insertion is O(N) in the transaction
2679+
* size, but it happens at most once per symref in a
2680+
* transaction. Make sure to add new_update->refname, which will
2681+
* be valid as long as affected_refnames is in use, and NOT
2682+
* referent, which might soon be freed by our caller.
2683+
*/
2684+
item = string_list_insert(affected_refnames, new_update->refname);
2685+
if (item->util)
2686+
BUG("%s unexpectedly found in affected_refnames",
2687+
new_update->refname);
26782688
item->util = new_update;
26792689

26802690
return 0;

0 commit comments

Comments
 (0)