Negative index in array access
| Vulnerability potential | Medium |
| DDoS potential | None |
Negative index in array access can be a sign of issue
Impact
A negative array index addresses memory before the start of the array. For a
plain C array a[-1] is *(a - 1), which reads or writes the bytes preceding
the buffer — frequently another local variable, a saved register, or heap
metadata. The result is the same family of consequences as any out-of-bounds
access: silent corruption, wrong results, information disclosure, or a crash.
A negative index almost always signals a logic error — an unsigned/signed
confusion, an unchecked return value used as an index, or a counter that
underflowed.
Vulnerability potential
Negative indexing is an out-of-bounds access (CWE-787 / CWE-125) and carries the same security weight when the index is influenced by input.
- A negative write below the buffer can corrupt adjacent control data (return address, saved frame pointer, heap chunk headers), leading to control-flow hijack.
- A negative read can leak adjacent memory contents.
- A subtle trap: a value meant to be an index is often stored in a signed
int; if it is later compared only against an upper bound (i < len) and not against0, a negative value passes the check and is then used. If that same value is implicitly converted to an unsignedsize_tfor the access, it becomes a huge positive offset — a far-out-of-bounds access.
Technical details
Array subscripting performs pointer arithmetic with no lower-bound check, so a negative subscript simply produces a lower address. Whether it faults depends on the layout: a small negative offset usually stays within a mapped page and corrupts neighbours silently, while a large negative value may reach an unmapped page and crash.
Signed/unsigned interaction
The dangerous case is mixing the two. int i = -1; size_t n = strlen(s);
if (i < n) buf[i] = 0; — here i < n compares int to size_t, so i is
converted to a huge unsigned value, the guard fails to protect, and the eventual
buf[i] (with i as int) still indexes below the buffer. Either branch of
the confusion is a bug.
Catching the issue
Compiler
-Wall -Wextra with -Wsign-compare and -Wsign-conversion flags the
signed/unsigned mismatches that produce negative indices. -Warray-bounds
catches some constant negative subscripts.
Sanitizers
AddressSanitizer reports the underflow access; UBSan’s -fsanitize=bounds
flags negative constant indices into known-size arrays. -fsanitize=signed-
integer-overflow helps catch the counter underflow that produced the index.
Static analysis
Clang Static Analyzer, Cppcheck, Coverity, and PVS-Studio track tainted and underflowed values used as indices.
Review
Validate indices against both 0 and the upper bound, prefer unsigned types
only when a negative value is truly impossible, and never use an unvalidated
return value (e.g. from a search function returning -1 on failure) directly as
a subscript.
How to reproduce
Compile with -fsanitize=address and run; ASan reports a
stack-buffer-underflow at the write.
#include <string.h>
int find(const char *s, char c)
{
const char *p = strchr(s, c);
return p ? (int)(p - s) : -1; /* -1 means "not found" */
}
int main(void)
{
int a[8] = {0};
int idx = find("hello", 'z'); /* not found -> idx == -1 */
/* idx is used without checking for -1 */
a[idx] = 1; /* writes a[-1], before the array */
return a[0];
}