# 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.

### Note

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

### Note

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.

Parent topic: Using the Pointer Checker