It is appropriate to perform pointer arithmetic only on pointers that reference elements of array objects.
Subclause 6.5.6 of the C Standard [ISO/IEC 9899:2011] states the following about pointer arithmetic:
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression.
Noncompliant Code Example
In this noncompliant code example, the programmer tries to access elements of the structure using pointer arithmetic. This practice is dangerous because fields in a structure are not guaranteed to be contiguous.
struct numbers { short num_a; short num_b; short num_c; }; int sum_numbers(const struct numbers *numb){ int total = 0; const short *numb_ptr; for (numb_ptr = &numb->num_a; numb_ptr <= &numb->num_c; numb_ptr++) { total += *(numb_ptr); } return total; } int main(void) { struct numbers my_numbers = { 1, 2, 3 }; sum_numbers(&my_numbers); return 0; }
Compliant Solution
It is possible to use the ->
operator to dereference each element of the structure:
total = numb->num_a + numb->num_b + numb->num_c;
However, this solution is likely to cause exactly the sort of painful experience the programmer who wrote the noncompliant code example was trying to avoid.
A better solution is to use an array, as in this compliant solution:
#include <stddef.h> int sum_numbers(const short *numb, size_t dim) { int total = 0; const short *numb_ptr; for (numb_ptr = numb; numb_ptr < numb + dim; numb_ptr++) { total += *(numb_ptr); } return total; } int main(void) { short my_numbers[9] = { 1, 2, 3 }; sum_numbers(my_numbers, sizeof(my_numbers)/sizeof(my_numbers[0])); return 0; }
Array elements are guaranteed to be contiguous in memory, so this solution is completely portable.
Exceptions
ARR37-EX1: All non-array objects in memory can be considered an array of one element. Adding one to such a pointer yields a pointer one element past the array, and subtracting one from that pointer yields the original pointer. This allows for code such as:
#include <stdlib.h> #include <string.h> struct s { char *str; /* Other fields */ }; struct s *create_s(const char *str) { struct s *ret; size_t len = strlen(str) + 1; ret = (struct s *)malloc(sizeof(struct s) + len); if (ret != NULL) { ret->str = (char *)(ret + 1); memcpy(ret + 1, str, len); } return ret; }
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ARR37-C | Medium | Probable | Medium | P8 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
|
|
|
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | ARR37-CPP. Do not add or subtract an integer to a pointer to a non-array object |
MITRE CWE | CWE-469, Use of pointer subtraction to determine size |
Bibliography
[Banahan 2003] | Section 5.3, "Pointers" Section 5.7, "Expressions Involving Pointers" |
[ISO/IEC 9899:2011] | Subclause 6.5.6, "Additive Operators" |
[VU#162289] |