diff options
author | Patrick Steinhardt <ps@pks.im> | 2020-06-30 10:13:26 +0200 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2020-07-12 16:01:21 +0200 |
commit | 349874474896d69979338961ee5813c146f561fb (patch) | |
tree | bbc47294d6f8a231c5a55140455dbb29f116e6ab | |
parent | b895547ca135158bf1582b50f6c09f8f78066e87 (diff) | |
download | libgit2-349874474896d69979338961ee5813c146f561fb.tar.gz |
refdb: avoid unlimited spinning in case of symref cyclespks/refdb-refactorings
To determine whether another reflog entry needs to be written for HEAD
on a reference update, we need to see whether HEAD directly or
indirectly points to the reference we're updating. The resolve logic is
currently completely unbounded except an error occurs, which effectively
means that we'd be spinning forever in case we have a symref loop in the
repository refdb.
Let's fix the issue by using `git_refdb_resolve` instead, which is
always bounded.
-rw-r--r-- | src/refdb.c | 19 |
1 files changed, 6 insertions, 13 deletions
diff --git a/src/refdb.c b/src/refdb.c index 6879b6aab..fb86d5ccb 100644 --- a/src/refdb.c +++ b/src/refdb.c @@ -326,7 +326,7 @@ int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference * int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref) { - git_reference *head = NULL, *peeled = NULL; + git_reference *head = NULL, *resolved = NULL; const char *name; int error; @@ -344,22 +344,15 @@ int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_refere goto out; /* Go down the symref chain until we find the branch */ - while (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC) { - if ((error = git_refdb_lookup(&peeled, db, git_reference_symbolic_target(head))) < 0) - break; - - git_reference_free(head); - head = peeled; - peeled = NULL; - } - - if (error < 0) { + if ((error = git_refdb_resolve(&resolved, db, git_reference_symbolic_target(head), -1)) < 0) { if (error != GIT_ENOTFOUND) goto out; error = 0; name = git_reference_symbolic_target(head); + } else if (git_reference_type(resolved) == GIT_REFERENCE_SYMBOLIC) { + name = git_reference_symbolic_target(resolved); } else { - name = git_reference_name(head); + name = git_reference_name(resolved); } if (strcmp(name, ref->name)) @@ -368,7 +361,7 @@ int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_refere *out = 1; out: - git_reference_free(peeled); + git_reference_free(resolved); git_reference_free(head); return error; } |