From: Karthik Nayak Date: Fri, 26 Sep 2025 07:44:13 GMT Subject: Re: [PATCH v2] refs/ref-cache: fix SEGFAULT when seeking in empty directories Message-ID: In-Reply-To: Karthik Nayak writes: > Junio C Hamano writes: > >> Karthik Nayak writes: >> >>> diff --git a/refs/ref-cache.c b/refs/ref-cache.c >>> index c180e0aad7..e5e5df16d8 100644 >>> --- a/refs/ref-cache.c >>> +++ b/refs/ref-cache.c >>> @@ -539,7 +539,7 @@ static int cache_ref_iterator_seek(struct ref_iterator *ref_iterator, >>> */ >>> break; >>> } >>> - } while (slash); >>> + } while (slash && dir->nr); >>> } >> >> This is at the tail of a "do { ... } while (...);" loop, but inside >> the loop I see this construct: >> >> for (idx = 0; idx < dir->nr; idx++) { >> cmp = strncmp(refname, dir->entries[idx]->name, len); >> if (cmp <= 0) >> break; >> } >> /* don't overflow the index */ >> idx = idx >= dir->nr ? dir->nr - 1 : idx; >> >> i.e., if we scan all the dir->entries[] elements in the innter loop >> and did not find any hit, idx would become dir->nr and this inner >> loop runs to the end. If (dir->nr == 0), then ?: operator [*] would >> become the idx = (dir->nr - 1); And that idx is used for a while >> before we get to this "while (slash && dir->nr)". >> > > This wouldn't happen because before the loop starts, we set: > > dir = get_ref_dir(iter->cache->root); > > So, `dir` will always have an entry (i.e. 'refs') in the first > iteration, after that, the checks in the while section of the 'do {} > while (...)' loop will kick in. > >> And then tha tis used like this. >> >> if (slash) >> slash = slash + 1; >> >> level->index = idx; >> if (dir->entries[idx]->flag & REF_DIR) { >> ... >> >> IOW, isn't this check a bit too late? I wonder if we can leave at >> the beginning of the outer loop, even before sort_ref_dir(dir), when >> dir->nr is zero, or something? >> >> > > We could add it there too. I can't see the merit of one over the other. > But if you see it being more readable. I'll happily make that change. > Just to clarify, I will hold off on re-rolling till we make a decision around this, as if we decide to keep the check as it currently is, there is no reason to re-roll. [snip]