Summary
A pattern of the form .{0,N}literal.{0,M} with two sufficiently large
bounded wildcard intervals causes pathological memory growth during regex
compilation, continuing until an external memory limit or host exhaustion
terminates the process. A 1-byte input file is enough to trigger it. On an
uncapped host this exhausted all RAM and swap (we observed a single ugrep
process reach ~11 GiB anonymous memory in a real incident that took a
self-hosted server running live services offline for ~30 minutes before
the kernel OOM killer intervened); inside a 512 MiB cgroup it reaches the
cap and is OOM-killed within seconds.
Reproduction (memory-caged — recommended)
printf 'x' > f.txt
sudo systemd-run --wait --pipe \
--unit=ugrep-oom-repro \
--uid="$(id -u)" \
-p MemoryMax=512M \
-p MemorySwapMax=0 \
-p RuntimeMaxSec=30 \
-p OOMPolicy=kill \
-- ugrep -E '.{0,70}dream.{0,90}' f.txt
The core command, shown bare only for illustration — running it uncaged
will consume all available memory:
ugrep -E '.{0,70}dream.{0,90}' f.txt
Results on all builds we tested (Ubuntu 24.04, x86_64):
| Build |
Source |
Result |
Runtime to 512 MiB cap |
| ugrep 5.0.0 |
Ubuntu 24.04 package 5.0.0+dfsg-1 |
cgroup OOM-kill |
3.9 s |
| ugrep 7.5.0 |
built from tag v7.5.0 (eada75555a2b), ALL TESTS PASSED |
cgroup OOM-kill |
3.9 s |
| ugrep 7.8.2 |
built from tag v7.8.2, ALL TESTS PASSED |
cgroup OOM-kill |
5.7 s |
All three used the same printf 'x' fixture and the same
-E '.{0,70}dream.{0,90}' pattern.
Narrowing (each verified in the same 512 MiB cage)
- Within this tested pattern family, both intervals are required to
trigger the failure: .{0,70}dream and dream.{0,90} each complete
instantly (~8 MiB peak). The paired form explodes.
- Interval size matters: paired
.{0,8}dream.{0,8} completes
instantly; paired {0,70}/{0,90} exhausts memory.
- The failure is independent of input size and content in all tested
cases: a 1-byte file, 4 MB of y\n lines (zero matches), a single
800 KB line with zero matches, and a 60 MB text fixture behave
identically. -o, -i, and file-vs-stdin delivery make no difference.
- Attribution to compilation: the 1-byte, zero-match reproducer and
the input ablations show that the growth is attributable to pattern
compilation rather than input scanning.
-P (PCRE2) is unaffected where available: the identical pattern
with -P completes instantly (~7-8 MiB) on the Ubuntu 5.0.0 package and
on a PCRE2-enabled 7.5.0 build, for both the 1-byte file and the 60 MB
fixture. (Our from-tag builds above were compiled without PCRE2 —
option -P is not available in this build configuration — so -P was
not testable on those two binaries; this is a build-configuration fact,
not a -P failure.)
- GNU grep (
grep -E, 3.11) handles the same pattern and inputs in
MiB-scale memory.
Expected
Bounded memory during pattern compilation, or a graceful diagnostic when
the compiled DFA would exceed a safe complexity or memory limit.
Context
This was discovered through ugrep 7.5.0 embedded in Anthropic's Claude
Code CLI, which transparently shadows grep. Multiple downstream
incidents are documented in anthropics/claude-code#67021. A later
downstream report also reproduces the corresponding escaped BRE form
through -G; the upstream stock-build matrix reported here specifically
verifies the POSIX ERE -E form.
Related reports
Environment
Ubuntu 24.04, x86_64; tag builds via ./build.sh (gcc); distribution
package from the Ubuntu archive.
Happy to test patches or provide more measurements.
AI-assisted investigation; all measurements were operator-verified.
Summary
A pattern of the form
.{0,N}literal.{0,M}with two sufficiently largebounded wildcard intervals causes pathological memory growth during regex
compilation, continuing until an external memory limit or host exhaustion
terminates the process. A 1-byte input file is enough to trigger it. On an
uncapped host this exhausted all RAM and swap (we observed a single ugrep
process reach ~11 GiB anonymous memory in a real incident that took a
self-hosted server running live services offline for ~30 minutes before
the kernel OOM killer intervened); inside a 512 MiB cgroup it reaches the
cap and is OOM-killed within seconds.
Reproduction (memory-caged — recommended)
The core command, shown bare only for illustration — running it uncaged
will consume all available memory:
ugrep -E '.{0,70}dream.{0,90}' f.txtResults on all builds we tested (Ubuntu 24.04, x86_64):
5.0.0+dfsg-1v7.5.0(eada75555a2b),ALL TESTS PASSEDv7.8.2,ALL TESTS PASSEDAll three used the same
printf 'x'fixture and the same-E '.{0,70}dream.{0,90}'pattern.Narrowing (each verified in the same 512 MiB cage)
trigger the failure:
.{0,70}dreamanddream.{0,90}each completeinstantly (~8 MiB peak). The paired form explodes.
.{0,8}dream.{0,8}completesinstantly; paired
{0,70}/{0,90}exhausts memory.cases: a 1-byte file, 4 MB of
y\nlines (zero matches), a single800 KB line with zero matches, and a 60 MB text fixture behave
identically.
-o,-i, and file-vs-stdin delivery make no difference.the input ablations show that the growth is attributable to pattern
compilation rather than input scanning.
-P(PCRE2) is unaffected where available: the identical patternwith
-Pcompletes instantly (~7-8 MiB) on the Ubuntu 5.0.0 package andon a PCRE2-enabled 7.5.0 build, for both the 1-byte file and the 60 MB
fixture. (Our from-tag builds above were compiled without PCRE2 —
option -P is not available in this build configuration— so-Pwasnot testable on those two binaries; this is a build-configuration fact,
not a
-Pfailure.)grep -E, 3.11) handles the same pattern and inputs inMiB-scale memory.
Expected
Bounded memory during pattern compilation, or a graceful diagnostic when
the compiled DFA would exceed a safe complexity or memory limit.
Context
This was discovered through ugrep 7.5.0 embedded in Anthropic's Claude
Code CLI, which transparently shadows
grep. Multiple downstreamincidents are documented in anthropics/claude-code#67021. A later
downstream report also reproduces the corresponding escaped BRE form
through
-G; the upstream stock-build matrix reported here specificallyverifies the POSIX ERE
-Eform.Related reports
growth for leading-wildcard patterns, but does not include this 1-byte
OOM reproducer or verification through ugrep 7.8.2.
incidents and the same minimal pattern family.
Environment
Ubuntu 24.04, x86_64; tag builds via
./build.sh(gcc); distributionpackage from the Ubuntu archive.
Happy to test patches or provide more measurements.
AI-assisted investigation; all measurements were operator-verified.