VNX-825: Expired Pointer Dereference
Reports C and C++ pointers, references and iterators kept past the lifetime of their target: a local's address stored through an out-parameter, in a global or in a field of a pointer parameter, a pointer to a block-scoped local used after the block, and C++ iterators or references used after the container may have reallocated.
| Field | Value |
|---|---|
| Rule ID | VNX-825 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | C, C++ |
| CWE | CWE-825 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | dangling-pointer iterator-invalidation cwe-825 c cpp memory-safety |
| Source | internal/sast/rules/vnx-825.rego |
Overview
VNX-825 maps to CWE-825: Expired Pointer Dereference. It reports five shapes in C and C++:
- The address of a non-static local (
&x, or a local array) stored through a pointer-to-pointer parameter (*out = &value;,*result = buf;). Also a field of a pointer parameter (c->label = buf;) not overwritten later in the function. - The same address stored in a file-scope pointer (
active = &cfg;) that the function does not reset before it returns. - A pointer assigned the address of a local declared inside an inner block and used after that block closes.
- In C++, an iterator, reference or pointer taken from a
std::vector,std::stringorstd::deque(begin(),front(),data(),c_str(),&v[i]) used after a call that can reallocate the container (push_back,insert,resize,erase,+=, …), and a range-for whose body grows or shrinks the container it iterates.
Not reported: static and heap storage, a global restored later in the function, uses inside the block that owns the local, iterators refreshed after the modification (it = v.erase(it)), node containers such as std::list and std::map, comments and string literals. Returning a local’s address is VNX-562; use after free() is VNX-C-004.
Why This Matters
The pointer outlives the object: the stack frame is reused by the next call, or the vector moved its elements to a new allocation. Every later access reads or writes memory that now belongs to something else.
What Gets Flagged
int value = atoi(s);
*out = &value; /* FLAGGED: caller gets a dead stack address */
auto it = items.begin();
items.push_back(extra);
*it = 0; /* FLAGGED: push_back may have reallocated */
Remediation
- Return values by copy, or store heap or caller-owned storage in out-parameters and globals.
- Re-acquire iterators, references and
c_str()/data()pointers after any call that can reallocate the container. - Do not modify a container inside a range-for over it; collect changes and apply them after the loop.
References
- CWE-825: Expired Pointer Dereference
- SEI CERT DCL30-C: Declare objects with appropriate storage durations
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-825
// nosec vnx-825
Or record an ignore rule: vulnetix ignore add --rule vnx-825 --reason "...". See Suppressing findings.