If there are remaining locks held when we free a transaction, make sure that
we release them instead of relying on the atexit magic to release them for
us. Otherwise, if we perform two transactions on the same ref and the first
transaction is aborted then the second transaction will fail to lock the ref.
This can currently not trigger since there are no commands that use multiple
transactions.

This sequence illustrates the bug:

t = transaction_begin()  /* first transaction */
transaction_update_sha1(t, ref, ...)  /* ref is locked */
transaction_free(t)

t = transaction_begin() /* second transaction */
transaction_update_sha1(t, ref, ...) /* will fail since ref was locked above */

Signed-off-by: Ronnie Sahlberg <sahlb...@google.com>
---
 refs.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/refs.c b/refs.c
index 87cdd91..17feec5 100644
--- a/refs.c
+++ b/refs.c
@@ -3325,6 +3325,8 @@ void transaction_free(struct ref_transaction *transaction)
                return;
 
        for (i = 0; i < transaction->nr; i++) {
+               if (transaction->updates[i]->lock)
+                       unlock_ref(transaction->updates[i]->lock);
                free((char *)transaction->updates[i]->committer);
                free((char *)transaction->updates[i]->msg);
                free(transaction->updates[i]);
@@ -3729,8 +3731,10 @@ cleanup:
          : REF_TRANSACTION_CLOSED;
 
        for (i = 0; i < n; i++)
-               if (updates[i]->lock)
+               if (updates[i]->lock) {
                        unlock_ref(updates[i]->lock);
+                       updates[i]->lock = NULL;
+               }
        return ret;
 }
 
-- 
2.0.0.rc3.506.g3739a35

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to