NationalSecurityAgency/ghidra · critical
%s: %s
Error message
%s: %s
What it means
cplus-dem's fatal(str) prints '<program_name>: <str>' to stderr and calls exit(1). It is the library's unrecoverable-error path; the one in-tree caller shown is xmalloc, which calls fatal("virtual memory exhausted") when malloc returns 0. So in practice this message means an allocation failed and the process is terminating immediately.
Source
Thrown at GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/cplus-dem.c:5303
fflush (stdout);
}
if (c == EOF)
break;
putchar (c);
if (c == '\n')
fflush (stdout);
}
}
return (0);
}
static void
fatal (str)
const char *str;
{
fprintf (stderr, "%s: %s\n", program_name, str);
exit (1);
}
PTR
xmalloc (size)
size_t size;
{
register PTR value = (PTR) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
PTR
xrealloc (ptr, size)
PTR ptr;
size_t size;
{View on GitHub (pinned to d5f144c24d)
Solutions
- Run the demangler under a memory limit (ulimit -v, or container cgroup) to bound exposure, then reject inputs that exceed it.
- Inspect/sanitize the input mangled name for pathological patterns before demangling (size caps, depth caps).
- Increase available memory / reduce concurrent load if the host is genuinely constrained.
- Update the demangler/libiberty; some historical unbounded-allocation bugs in demangling are fixed in newer versions.
Example fix
// before - run demangler on unbounded untrusted input $ cat huge_symbols.txt | while read s; do c++filt "$s"; done // after - cap per-invocation memory and input size $ ulimit -v 262144 # 256 MB virtual cap $ awk 'length($0) < 4096' huge_symbols.txt | while read s; do c++filt "$s"; done
Defensive patterns
Strategy: fallback
Validate before calling
// Cap per-invocation memory and input size before demangling
// (shell) ulimit -v 262144 # 256 MB
// (input gate) skip lines longer than a safe bound before piping to the demangler
if (strlen(mangled) > MAX_SAFE_NAME) { /* skip or truncate */ } Type guard
boolean isPlausiblySafeInput(String s) {
return s != null && s.length() < 4096 && s.chars().filter(c -> c == 'N').count() < 1000; // crude depth/size guard
} Try / catch
// fatal() calls exit(1); cannot be caught inside the demangler process.
// Run it as a child and treat non-zero exit / 'virtual memory exhausted' as a hard reject:
int rc = run_child_with_limits({"c++filt", symbol}, memLimitBytes);
if (rc != 0) {
/* skip this symbol; treat as untrusted/pathological */
} Prevention
- Run the demangler under a memory cap (ulimit -v or container cgroup).
- Cap input name length and template-nesting depth before demangling.
- Process untrusted symbol streams one-at-a-time so one bad input cannot abort a batch.
- Keep the demangler/libiberty updated to pick up allocation-bug fixes.
When it happens
Trigger: Any allocation inside the demangler (xmalloc/xrealloc family) returning NULL/0, which routes to fatal(). With the standard caller this means the process ran out of memory while demangling (e.g. an adversarial/pathological mangled name causing huge allocation, or the host is genuinely OOM).
Common situations: Processing an extremely large or pathological mangled name that triggers a huge allocation; running the demangler on an untrusted input stream without memory limits; host under memory pressure or container memory cgroup hit; a bug causing unbounded allocation.
Related errors
- %s: error: too many @-files encountered
- Failed: %s (status %d)
- Failed: %s
- %s: unknown demangling style `%s'
- %s: option `%s' is ambiguous
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/17530a535a2dc17d.
Report an issue: GitHub.