Signal Stack

B2B technology signals above the noise.

Decision Guides · 6 min read

The malloc Segmentation Fault Isn’t Always a Null-Check Bug

A malloc call that returns a valid pointer and passes a NULL check can still be the root cause of a later segfault. Two disclosed heap-overflow cases show the actual mechanism: the code that sizes the allocation and the code that writes into it can disagree about what they're measuring.

The malloc Segmentation Fault Isn’t Always a Null Check

A C program that segfaults right after a malloc call is not proof that malloc itself failed. Stack Overflow’s memory tag shows the more common bug: developers treat a successful allocation as a guarantee and skip the failure check, which only matters for the narrow case where the allocator itself refuses the request. The malloc segmentation fault question is less about the allocator and more about what the caller later does with the pointer it returns.

The tempting read is to blame missing NULL checks alone. One widely discussed question in the tag asks plainly whether skipping the allocation-failure check is problematic in C++, and the replies split between always-check and the observation that a Linux process will often be killed by the OOM killer before malloc ever actually returns NULL. That disagreement matters: the check guards a real but narrow failure mode, not general memory corruption.

A second Stack Overflow thread from the same period asks how to partition a 10 MiB region reserved with a single mmap() call into blocks for a hand-written C allocator. Bugs in that kind of block-partitioning logic produce the same symptom as a missed null check: a segfault that surfaces far from the code that actually corrupted memory.

Why the Buffer-Size Math Fails Under Load

The more instructive mechanism comes from a disclosed nginx heap overflow, CVE-2026-42533. Its rewrite engine sizes an output buffer in a first pass and writes into it in a second pass, and both passes read the same shared regex-capture state. When a map’s regex evaluation overwrites that state between the two passes, the buffer ends up sized for one capture and filled from another.

That is the pattern worth generalizing: a malloc call can be syntactically correct, checked for NULL, and still undersized, because the size computation and the write logic disagree about what they are measuring. The fix, per F5’s advisory, is nginx 1.30.4, 1.31.3, or NGINX Plus 37.0.3.1; every version from 0.9.6 through 1.31.2 is described as vulnerable to the underlying pattern.

A second disclosed case makes the same mechanism concrete in an archive parser rather than a web server. CVE-2026-48095 in 7-Zip’s NTFS handler lets crafted metadata drive a 32-bit shift calculation into undefined behavior, so the program allocates a one-byte input buffer and then copies as much as 256 MB of attacker-controlled data into it in 64 KB iterations.

Both disclosed bugs share a root-cause shape: an unchecked computation or a shared-state read feeds the malloc size argument, and a write proceeds independently of that allocation. Debian’s own tracker lists a wide population of small, single-purpose C tools with CVE entries described plainly as segmentation fault or heap buffer overflow, a reminder that this defect class is routine triage material, not an edge case.

Case Root cause Fixed release Score
nginx CVE-2026-42533 Two-pass buffer sizing reads shared capture state overwritten between passes nginx 1.30.4 / 1.31.3 9.2 CVSS v4
7-Zip CVE-2026-48095 Unchecked 32-bit shift drives a one-byte allocation before a much larger write 7-Zip 26.01 (26.02 current) 8.8 CVSS v3.1

What a Precise Checker Confirms That a Stack Trace Cannot

Clang’s own documentation states that its optimizer assumes compiled code contains no undefined behavior, and that when undefined behavior is present anyway, the resulting behavior can change depending on the optimization level in use. That single fact explains why a malloc-adjacent bug can run clean in a debug build and only segfault after optimization is enabled.

On the detection side, NVIDIA’s Compute Sanitizer suite illustrates what a purpose-built checker actually verifies rather than assumes. Its memcheck tool is described as capable of precisely detecting and attributing out-of-bounds and misaligned memory access errors, and a separate initcheck tool reports cases where a kernel reads uninitialized global memory before it has been written.

The equivalent discipline applies on the CPU side even though Compute Sanitizer itself targets CUDA kernels rather than general C binaries: precise attribution beats plausible speculation. A crash report that says segfault near a given line is a starting point, not a diagnosis, until a tool that tracks the actual read or write boundary confirms which allocation was violated.

Neither of the two tempting fixes resolves the mechanism above. Adding a NULL check after malloc guards only the case where the allocator refuses the request; it does nothing for a buffer the allocator happily returns and a downstream computation then overflows. Rewriting the allocator’s internal partitioning logic only matters if that layer is the one computing the faulty size in the first place.

The smallest discriminating check is not whether malloc returns NULL but whether the byte count passed to malloc matches the byte count actually written, under the same inputs that reach production. The nginx and 7-Zip cases both show this equality can hold under common inputs and fail only under a specific, workload-shaped configuration.

In the nginx case, the researcher who published analysis beyond F5’s advisory confirmed a second, narrower exploitation path with AddressSanitizer rather than source reading alone, and F5’s own advisory does not mention that second path. That is the discriminating move worth copying: verify a size-versus-write mismatch with an instrumented build before trusting a manual argument.

F5 credited the nginx fix to Winfunc Research’s Mufeed VH and maintainer Maxim Dounin, and noted more than a dozen researchers had reported the underlying issue independently, a signal that the trigger condition is reachable through ordinary fuzzing rather than an obscure configuration accident.

Fix Options and Their Trade-offs

For an application-level malloc bug that mirrors this pattern, the fix options split cleanly. A source-level change that unifies the size-computation and the write path into a single pass removes the discrepancy at its root, and that is also the only complete fix in the nginx precedent.

F5’s interim mitigation for nginx, switching affected regex maps to named captures, closes the main path but leaves a narrower one open when a named group collides with the location regex, which the researcher confirmed separately. Treat any config-only mitigation for a malloc-sizing bug the same way: assume it narrows exposure rather than closing it, until the source fix ships.

Compute Sanitizer’s design argument generalizes past its GPU-specific scope: NVIDIA frames the suite as necessary because the volume of memory-access errors increases substantially as thread count grows, which is why targeted checkers replace manual review at scale. The same argument applies to CPU C code, where manual size-path review does not scale past a handful of call sites.

What to Verify Before Calling a Fix Complete

Before treating a malloc-adjacent segfault as resolved, three things need direct confirmation rather than inference. First, whether the size argument passed to the allocator and the byte count in the subsequent write are computed from the same input state, not two reads of state that can be evaluated out of order.

Second, whether the fix has been exercised under an instrumented build rather than just re-read, since the nginx case shows a documented mitigation can still miss a second code path that only a sanitizer run surfaced.

Third, whether the allocation-failure path, if the code checks malloc’s return value at all, is itself tested, since Stack Overflow’s own discussion shows practitioners disagree about how often that path is even reachable on a modern Linux system with overcommit enabled. If none of those three checks has a documented answer, the malloc segmentation fault is diagnosed, not fixed.