When two pointers are subtracted, both must point to elements of the same array object or to one past the last element of the array object (C Standard, subclause 6.5.6 [ISO/IEC 9899:2011]); the result is the difference of the subscripts of the two array elements. Otherwise, the operation results in undefined behavior. (See undefined behavior 48 of Appendix J.) This restriction exists because pointer subtraction in C produces the number of objects between the two pointers, not the number of bytes.
Similarly, comparing pointers using the relational operators <
, <=
, >=
, and >
gives the positions of the pointers relative to each other. Subtracting or comparing pointers that do not refer to the same array results in undefined behavior. (See undefined behavior 48 and undefined behavior 53 of Appendix J.)
Comparing pointers using the equality operators ==
and !=
has well-defined semantics regardless of whether or not either of the pointers is null, points into the same object, or points one past the last element of an array object or function.
It is acceptable to subtract or compare two member pointers within a single struct
object, suitably cast because any object can be treated as an array of unsigned char
. However, when doing so, remember to account for the effects of alignment and padding on the structure. See ARR39-C. Do not add or subtract a scaled integer to a pointer for more information.
Noncompliant Code Example
In this noncompliant code example, pointer subtraction is used to determine how many free elements are left in the nums
array:
#include <stddef.h> enum { SIZE = 32 }; void func(void) { int nums[SIZE]; int end; int *next_num_ptr = nums; size_t free_elements; /* Increment next_num_ptr as array fills */ free_elements = &end - next_num_ptr; }
This program incorrectly assumes that the nums
array is adjacent to the end
variable in memory. A compiler is permitted to insert padding bits between these two variables, or even reorder them in memory.
Compliant Solution
In this compliant solution, the number of free elements is computed by subtracting next_num_ptr
from the address of the pointer past the nums
array. While this pointer may not be dereferenced, it may be used in pointer arithmetic.
#include <stddef.h> enum { SIZE = 32 }; void func(void) { int nums[SIZE]; int *next_num_ptr = nums; size_t free_elements; /* Increment next_num_ptr as array fills */ free_elements = &(nums[SIZE]) - next_num_ptr; }
Exceptions
ARR36-EX1: Comparing two pointers within the same object is allowed.
ARR36-EX2: Subtracting two pointers to char
within the same object is allowed.
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ARR36-C | Medium | Probable | Medium | P8 | L2 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
9.7.1 | 438 S | Fully implemented | |
PRQA QA-C | Unable to render {include} The included page could not be found. | 0487 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C++ Secure Coding Standard | ARR36-CPP. Do not subtract or compare two pointers or iterators that do not refer to the same array or container |
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" |