[BUG] Grep tool hangs indefinitely with .{0,40}X.{0,40}-style regex (ugrep); orphaned child process survives shell termination
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code's built-in Grep tool (backed by a bundled ugrep) can hang for many minutes — in our case, 20+ minutes before we manually killed it — on a tiny input when the regex has a bounded-repetition wildcard on both sides of the actual match, e.g. .{0,40}PATTERN.{0,40}. We isolated this to a minimal, fully reproducible case (below) using the standalone, published ugrep binary (v7.8.2 via Homebrew) — independent of Claude Code entirely — so the root cause appears to live in ugrep itself, not in Claude Code's integration.
Separately, we also observed that when the wrapping background shell is terminated, the underlying ugrep process is not terminated with it — it becomes an orphan (reparented to PID 1) and keeps consuming ~90-100% CPU indefinitely until manually kill -9'd.
What Should Happen?
Matching a single short line against a simple bounded-repetition pattern should complete near-instantly and scale roughly linearly with the bound size — not go from instant at N=20 to effectively hung at N=40.
Error Messages/Logs
Steps to Reproduce
brew install ugrep # v7.8.2 at time of testing
printf 'Sample analysis indicates a positive trend across replicates for batch 1, ratio test X70 / Y30 concentration noted.' > mini.txt
# Hangs indefinitely (killed after 5s via timeout; CPU pinned ~95-100% the whole time):
timeout 5 ugrep -G -oE '.{0,40}X ?70.{0,40}' mini.txt # exit 124, never produced output
# Near-instant with a slightly smaller bound, same input, same pattern shape:
timeout 5 ugrep -G -oE '.{0,20}X ?70.{0,20}' mini.txt # completes in ~0.05s
We narrowed this down further; the hang does not depend on: alternation (single literal branch reproduces it just as reliably), -o (dropping it, plain -E, still hangs), -G vs -E (both hang identically), or CJK/multi-byte text (reproduces on pure ASCII).
It does depend on the bound size on both sides simultaneously: on the exact same one-line input, .{0,20}...{0,20} completes in ~50ms, while .{0,40}...{0,40} never completes. We didn't bisect the exact transition point, but 20 vs 40 alone is already a >100x slowdown — consistent with an exhaustive search over both bounded quantifiers (e.g. for POSIX leftmost-longest matching) rather than an early-exit/anchored search.
This is a single ~120-byte, single-line input — no large file or corpus is needed to trigger a hang that scales from milliseconds to (in our real-world case) tens of minutes.
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.207
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
Ghostty terminal emulator
Secondary issue: orphaned child process on shell termination
When we sent SIGTERM to the background shell running the stuck search, the shell exited, but its ugrep child was not terminated with it — it was reparented to PID 1 and kept running until manually SIGKILL'd. Practical impact: stopping a runaway search by killing the wrapping shell/task doesn't actually free the CPU.
Suggested next steps
- The regex-performance issue looks upstream in ugrep itself — may be worth relaying to github.com/Genivia/ugrep too, if not already known there.
- Regardless, it'd help for Claude Code's Grep tool to enforce a subprocess timeout, and ensure child processes are actually terminated when the wrapping shell/task is stopped.