IGNOGlob catastrophic backtracking — ReDoS from an untrusted .gitignore
dog/git/IGNO.c's IGNOGlob (IGNO.c:24-66) recurses on EVERY */** suffix with no memoization and no step budget: for(;;){ if(IGNOGlob(pat,tail)) return YES; if(empty) break; used1(tail); } (:36-40, :46-51). A single crafted pattern like *a*a*a*…*a*b matched against a long non-matching path is exponential-time, and ** nesting compounds it. .gitignore files come from cloned/untrusted repositories, and every worktree scan (be status, diff, post) routes through IGNOMatch per chain-file × per pattern (≤256) × per path prefix — so a hostile repo shipping a crafted .gitignore hangs the process. Method: Issues.
IGNO.c:24-66 recursive matcher; pattern length bounded only by the mmap'dfile, so ~40 wildcards effectively hangs.
.gitignore from a clone; IGNOMatch fans it across chainfiles, ≤256 patterns, and path prefixes.
wildmatch` technique) OR a hard recursion/step budget that fails closed.
dog/git libdog, ABC style; behaviour-preserving on the existing IGNO tests.algorithm fix and the slice cleanup together to avoid touching it twice.
*a*…*b against a long non-match; assertit completes under a step budget (dog/fuzz has no IGNO target today).
79612854 — unbudgeted recursion still at IGNO.c:24-51. NOTHING landed; a budgeted igno_glob (IGNO_GLOB_BUDGET 200000, fail-closed) IS implemented in worktree ~/src/DOG-015 (git/IGNO.c), UNLANDED.