Developer Guide and Reference

Contents

How the Compiler Defines Bounds Information for Pointers

The pointer checker is not supported on
macOS*
systems.
The following defines how the compiler determines the bound information for pointers.
In each section,
lower_bound(
p
)
refers to the lower bound associated with
p
and
upper_bound(
p
)
refers to the upper bound associated with
p
.
Pointers created by the alloca() function
p = alloca(size); // lower_bound (p) is (char *)p // upper_bound (p) is lower_bound(p) + size - 1
Pointers created by the calloc() function
p = calloc(num, size); // lower_bound(p) is (char *)p // upper_bound(p) is lower_bound(p) + size * num - 1
Pointers created by the
malloc()
function
p = malloc(size); // lower_bound(p) is (char *)p // upper_bound(p) is lower_bound(p) + size - 1
Pointers created by casting
p = (T *)q; // lower_bound(p) is lower_bound(q) // upper_bound(p) is upper_bound(q)
Casting a pointer does not affect the bounds of a pointer. If you cast a pointer to a new type that is larger than the bounds associated with the original pointer, you will get an out-of-bounds error when you try to access any member or element outside the original bounds. If you cast a pointer to a smaller type than the original pointer, you can still access the original data.
Pointers created for a variable length array in a structure
typedef struct { int num; int a[]; } T; q = malloc(sizeof(T) + sizeof(int) * num); p = &q->a; // lower_bound(p) is (char *)&q->a // upper_bound(p) is upper_bound(q)
When you define an array as the last member of a structure, the upper bound is not narrowed and is allowed to access all of the array elements allocated by the
malloc()
function.
Pointers defined by the address (&) operator
p = &v; // lower_bound(p) is (char *)&v // upper_bound(p) is (char *)&v + sizeof(v) - 1 p = &v.m; // lower_bound(p) is (char *)&v + offsetof(typeof(v), m) // upper_bound(p) is lower_bound(p) + sizeof(v.m) – 1 p = &q->m; // lower_bound(p) is (char *)q + offsetof(typeof(*q), m) // upper_bound(p) is lower_bound(p) + sizeof(q->m) – 1
The bounds information is narrowed to the size of the member when you point to a member of a structure, union, or class.
Pointers defined by the new operator
p = new T; // lower_bound(p) is (char *)p // upper_bound(p) is lower_bound(p) + sizeof(T) - 1
Pointers defined by the addresses in an array
T a[X][Y]; p = a; p = &a[x]; p = &a[x][y]; // lower_bound(p) is (char *)a // upper_bound(p) is lower_bound(p) + sizeof(a) - 1
When you take the address of an element of an array or the address of a single row of a multi-dimensioned array, the bounds are not narrowed to the size of the element. You can increment or decrement the pointer throughout the array.
Incrementing and Decrementing Pointers
p = &a[x][y].m; // lower_bound(p) is (char *)&a[n][m] + offsetof(T, m) // upper_bound(p) is lower_bound(p) + sizeof(T.m) – 1
When you take the address of a member of an element, the bounds are narrowed to the size of the member.
Pointers defined by pointer copies
p = q; p = q + expr; p = q – expr; // lower_bound(p) is lower_bound(q) // upper_bound(p) is upper_bound(q)
The bounds are copied from
q
. Offsetting the pointer on the right does not affect the bounds.
Pointers defined by incrementing or decrementing a pointer
p++; p--; ++p; --p; p += expr; p -= expr;
The bounds do not change when you increment or decrement a pointer.