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
This commit is contained in:
commit
dafbe1993e
@ -2099,11 +2099,10 @@ static int split_head_update(struct ref_update *update,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* First make sure that HEAD is not already in the
|
* First make sure that HEAD is not already in the
|
||||||
* transaction. This insertion is O(N) in the transaction
|
* transaction. This check is O(lg N) in the transaction
|
||||||
* size, but it happens at most once per transaction.
|
* size, but it happens at most once per transaction.
|
||||||
*/
|
*/
|
||||||
item = string_list_insert(affected_refnames, "HEAD");
|
if (string_list_has_string(affected_refnames, "HEAD")) {
|
||||||
if (item->util) {
|
|
||||||
/* An entry already existed */
|
/* An entry already existed */
|
||||||
strbuf_addf(err,
|
strbuf_addf(err,
|
||||||
"multiple updates for 'HEAD' (including one "
|
"multiple updates for 'HEAD' (including one "
|
||||||
@ -2118,6 +2117,14 @@ static int split_head_update(struct ref_update *update,
|
|||||||
update->new_oid.hash, update->old_oid.hash,
|
update->new_oid.hash, update->old_oid.hash,
|
||||||
update->msg);
|
update->msg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add "HEAD". This insertion is O(N) in the transaction
|
||||||
|
* size, but it happens at most once per transaction.
|
||||||
|
* Add new_update->refname instead of a literal "HEAD".
|
||||||
|
*/
|
||||||
|
if (strcmp(new_update->refname, "HEAD"))
|
||||||
|
BUG("%s unexpectedly not 'HEAD'", new_update->refname);
|
||||||
|
item = string_list_insert(affected_refnames, new_update->refname);
|
||||||
item->util = new_update;
|
item->util = new_update;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2144,13 +2151,12 @@ static int split_symref_update(struct files_ref_store *refs,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* First make sure that referent is not already in the
|
* First make sure that referent is not already in the
|
||||||
* transaction. This insertion is O(N) in the transaction
|
* transaction. This check is O(lg N) in the transaction
|
||||||
* size, but it happens at most once per symref in a
|
* size, but it happens at most once per symref in a
|
||||||
* transaction.
|
* transaction.
|
||||||
*/
|
*/
|
||||||
item = string_list_insert(affected_refnames, referent);
|
if (string_list_has_string(affected_refnames, referent)) {
|
||||||
if (item->util) {
|
/* An entry already exists */
|
||||||
/* An entry already existed */
|
|
||||||
strbuf_addf(err,
|
strbuf_addf(err,
|
||||||
"multiple updates for '%s' (including one "
|
"multiple updates for '%s' (including one "
|
||||||
"via symref '%s') are not allowed",
|
"via symref '%s') are not allowed",
|
||||||
@ -2185,6 +2191,17 @@ static int split_symref_update(struct files_ref_store *refs,
|
|||||||
update->flags |= REF_LOG_ONLY | REF_NODEREF;
|
update->flags |= REF_LOG_ONLY | REF_NODEREF;
|
||||||
update->flags &= ~REF_HAVE_OLD;
|
update->flags &= ~REF_HAVE_OLD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the referent. This insertion is O(N) in the transaction
|
||||||
|
* size, but it happens at most once per symref in a
|
||||||
|
* transaction. Make sure to add new_update->refname, which will
|
||||||
|
* be valid as long as affected_refnames is in use, and NOT
|
||||||
|
* referent, which might soon be freed by our caller.
|
||||||
|
*/
|
||||||
|
item = string_list_insert(affected_refnames, new_update->refname);
|
||||||
|
if (item->util)
|
||||||
|
BUG("%s unexpectedly found in affected_refnames",
|
||||||
|
new_update->refname);
|
||||||
item->util = new_update;
|
item->util = new_update;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2256,7 +2273,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
struct strbuf referent = STRBUF_INIT;
|
struct strbuf referent = STRBUF_INIT;
|
||||||
int mustexist = (update->flags & REF_HAVE_OLD) &&
|
int mustexist = (update->flags & REF_HAVE_OLD) &&
|
||||||
!is_null_oid(&update->old_oid);
|
!is_null_oid(&update->old_oid);
|
||||||
int ret;
|
int ret = 0;
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
|
|
||||||
files_assert_main_repository(refs, "lock_ref_for_update");
|
files_assert_main_repository(refs, "lock_ref_for_update");
|
||||||
@ -2268,7 +2285,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
ret = split_head_update(update, transaction, head_ref,
|
ret = split_head_update(update, transaction, head_ref,
|
||||||
affected_refnames, err);
|
affected_refnames, err);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = lock_raw_ref(refs, update->refname, mustexist,
|
ret = lock_raw_ref(refs, update->refname, mustexist,
|
||||||
@ -2282,7 +2299,7 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
strbuf_addf(err, "cannot lock ref '%s': %s",
|
strbuf_addf(err, "cannot lock ref '%s': %s",
|
||||||
original_update_refname(update), reason);
|
original_update_refname(update), reason);
|
||||||
free(reason);
|
free(reason);
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
update->backend_data = lock;
|
update->backend_data = lock;
|
||||||
@ -2301,10 +2318,12 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
strbuf_addf(err, "cannot lock ref '%s': "
|
strbuf_addf(err, "cannot lock ref '%s': "
|
||||||
"error reading reference",
|
"error reading reference",
|
||||||
original_update_refname(update));
|
original_update_refname(update));
|
||||||
return -1;
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
} else if (check_old_oid(update, &lock->old_oid, err)) {
|
} else if (check_old_oid(update, &lock->old_oid, err)) {
|
||||||
return TRANSACTION_GENERIC_ERROR;
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
@ -2318,13 +2337,15 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
referent.buf, transaction,
|
referent.buf, transaction,
|
||||||
affected_refnames, err);
|
affected_refnames, err);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
struct ref_update *parent_update;
|
struct ref_update *parent_update;
|
||||||
|
|
||||||
if (check_old_oid(update, &lock->old_oid, err))
|
if (check_old_oid(update, &lock->old_oid, err)) {
|
||||||
return TRANSACTION_GENERIC_ERROR;
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this update is happening indirectly because of a
|
* If this update is happening indirectly because of a
|
||||||
@ -2361,7 +2382,8 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
"cannot update ref '%s': %s",
|
"cannot update ref '%s': %s",
|
||||||
update->refname, write_err);
|
update->refname, write_err);
|
||||||
free(write_err);
|
free(write_err);
|
||||||
return TRANSACTION_GENERIC_ERROR;
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
update->flags |= REF_NEEDS_COMMIT;
|
update->flags |= REF_NEEDS_COMMIT;
|
||||||
}
|
}
|
||||||
@ -2375,10 +2397,14 @@ static int lock_ref_for_update(struct files_ref_store *refs,
|
|||||||
if (close_ref(lock)) {
|
if (close_ref(lock)) {
|
||||||
strbuf_addf(err, "couldn't close '%s.lock'",
|
strbuf_addf(err, "couldn't close '%s.lock'",
|
||||||
update->refname);
|
update->refname);
|
||||||
return TRANSACTION_GENERIC_ERROR;
|
ret = TRANSACTION_GENERIC_ERROR;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
|
out:
|
||||||
|
strbuf_release(&referent);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user