From: Michael Haggerty <mhagger@xxxxxxxxxxxx> If there is a broken symlink where a loose reference file is expected, then the attempt to open() it fails with ENOENT. This error is misinterpreted to mean that the loose reference file itself has disappeared due to a race, causing the lookup to be retried. But in this scenario, the retries all suffer from the same problem, causing an infinite loop. So put a limit (of 5) on the number of times that the stat_ref step can be retried. Based-on-patch-by: Petr Stodulka <pstodulk@xxxxxxxxxx> Signed-off-by: Michael Haggerty <mhagger@xxxxxxxxxxxx> --- refs/files-backend.c | 6 ++++-- refs/refs-internal.h | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index d16feb1..245a0b5 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1353,6 +1353,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, int fd; int ret = -1; int save_errno; + int retries = 0; *type = 0; strbuf_reset(&sb_path); @@ -1390,7 +1391,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, if (S_ISLNK(st.st_mode)) { strbuf_reset(&sb_contents); if (strbuf_readlink(&sb_contents, path, 0) < 0) { - if (errno == ENOENT || errno == EINVAL) + if ((errno == ENOENT || errno == EINVAL) && + retries++ < MAXRETRIES) /* inconsistent with lstat; retry */ goto stat_ref; else @@ -1426,7 +1428,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, */ fd = open(path, O_RDONLY); if (fd < 0) { - if (errno == ENOENT) + if (errno == ENOENT && retries++ < MAXRETRIES) /* inconsistent with lstat; retry */ goto stat_ref; else diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 708b260..37e6b99 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -255,6 +255,12 @@ int rename_ref_available(const char *old_refname, const char *new_refname); /* We allow "recursive" symbolic refs. Only within reason, though */ #define SYMREF_MAXDEPTH 5 +/* + * We allow only MAXRETRIES tries to jump on stat_ref, because of possible + * infinite loop + */ +#define MAXRETRIES 5 + /* Include broken references in a do_for_each_ref*() iteration: */ #define DO_FOR_EACH_INCLUDE_BROKEN 0x01 -- 2.5.5