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; the result is the difference of the subscripts of the two array elements. Likewise, when two iterators are subtracted, both must refer to elements in the same container, or to the value returned by the end() method of the container. 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.

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.

Noncompliant Code Example (Arrays)

In this noncompliant code example pointer subtraction is used to determine how many free elements are left in the nums array.

int nums[SIZE];
char *strings[SIZE];
int *next_num_ptr = nums;
int free_bytes;

/* increment next_num_ptr as array fills */

free_bytes = strings - (char **)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 (Arrays)

In this compliant solution, the number of free elements is kept as a counter and adjusted on every array operation. It is also calculated in terms of free elements instead of bytes. This prevents further mathematical errors.

int nums[SIZE];
char *strings[SIZE];
int *next_num_ptr = nums;
int free_bytes;

/* increment next_num_ptr as array fills */

free_bytes = (&(nums[SIZE]) - next_num_ptr) * sizeof(int);

Noncompliant Code Example (Vectors)

In this noncompliant code example two iterators are subtracted that don't refer to the same vector.

vector<int> nums1(10, 0);
vector<int> nums2(10, 0);
vector<int>::iterator i1 = nums1.begin();
vector<int>::iterator i2 = nums2.begin();

int distance = i2 - i1;

Since C++ vector iterators are usually implemented as pointers to contiguous memory on the heap, much like array pointers, one might expect distance to have a value of 10. However the C++ standard leaves this as undefined. On Linux with G++ 4.3.2, distance receives an unexpected value of 12.

Compliant Solution (Vectors)

In this compliant solution, both iterators point to the same vector, and the distance variable receives the expected value of 10.

vector<int> nums1(10, 0);
vector<int> nums2(10, 0);
vector<int>::iterator i1 = nums1.begin();
vector<int>::iterator i2 = nums1.end();

int distance = i2 - i1;

Exceptions

ARR36-EX1: Comparing two pointers to char within the same object is allowed.

Risk Assessment

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

ARR36-CPP

medium

probable

medium

P8

L2

Automated Detection

Tool

Version

Checker

Description

 PRQA QA-C++

 


2761,2762,2763,2766,

2767,2768,2771,2772,

2773

 

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

This rule appears in the C Secure Coding Standard as ARR36-C. Do not subtract or compare two pointers that do not refer to the same array.

Bibliography

[Banahan 03] Section 5.3, "Pointers," and Section 5.7, "Expressions involving pointers"
[ISO/IEC 14882-2003] Section 5.7 "Additive operators"
[MITRE 07] CWE ID 469, "Use of Pointer Subtraction to Determine Size"


CTR35-CPP. Do not allow loops to iterate beyond the end of an array or container      06. Containers (CTR)      ARR37-CPP. Do not add or subtract an integer to a pointer to a non-array object