static_rtti
static_rtti

Reputation: 56342

Is accessing data outside an array incorrect if you don't use it?

In an algorithm I'm writing, I can have the following (simplified of course)

int a[3] = {1,2,3};
int b = a[3];

when the index used to fill b overflows, I never use the value of b. Is the code still incorrect? Do I have to make an explicit boundary check?

Upvotes: 6

Views: 505

Answers (6)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385325

Yes.

You are using the value, by copying it into b.

More specifically, dereferencing (a+3) is not allowed since the expression (a+3) is not a valid pointer... and the expression a[3] is equivalent to *(a+3) (where a has decayed to a pointer-expression).

Upvotes: 1

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133082

This code has Undefined Behavior whether or not you use b. Why? Because a[3] is equivalent to *(a+3) by definition. And here's a quote from the standard that proved that *(a+3) is in itself undefined, regardless of whether the value is stored, used, or left alone.

When an expression that has integral 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 integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

Upvotes: 5

Alexander Gessler
Alexander Gessler

Reputation: 46647

Reading a[3] already causes undefined behaviour. As undefined behaviour is never locally limited, this can already lead to your harddisk drive being formatted or your computer emerging to a giant, flesh-eating zombie.

In reality, it will usually just work. But it's easy to make up a case where the end of the array marks the end of a mapped memory region, so accessing one element beyond would cause a segmentation fault. This is certainly not the case for an array of int on the stack and neither with most heap implementations, but you shouldn't rely on it.

(Whether taking the address of &a[3] is undefined behaviour as well is heavily disputed.)

Upvotes: 3

Sander De Dycker
Sander De Dycker

Reputation: 16243

It's still incorrect yes, because you access the out-of-bounds memory location to get the value a[3] and store it in the variable b.

The fact that you never use b could mean that the compiler optimizes out that line of code, so you might not ever see any adverse effects from that line being there.

However, the compiler is not required to do so, and the code itself still has undefined behavior.

Upvotes: 2

Xeo
Xeo

Reputation: 131847

Still incorrect, still undefined behaviour. Do the bounds check.

int b = *(a + 3); // dereferencing beyond the array bound.

Upvotes: 3

Bo Persson
Bo Persson

Reputation: 92341

Yes, it is wrong to read a[3] which doesn't exits.

Using b would be wrong too, but it is already too late.

Upvotes: 0

Related Questions