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

  1. Run the demangler under a memory limit (ulimit -v, or container cgroup) to bound exposure, then reject inputs that exceed it.
  2. Inspect/sanitize the input mangled name for pathological patterns before demangling (size caps, depth caps).
  3. Increase available memory / reduce concurrent load if the host is genuinely constrained.
  4. 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

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


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/17530a535a2dc17d. Report an issue: GitHub.