1

My C++ book says that if I have

int anArray[25];

and I try to evaluate

anArray[25] = 0;

the program will simply overwrite whatever value is stored in the next memory address past the end of the array. Why?

My thinking is compilers are stupid in that regard. All the compiler cares to do is calculate where anArray[25] should be and then move on.

  • 5
    C++ favors performance over safety. It expects you to already know what you are doing well enough to avoid accesses beyond the end of the array. – Robert Harvey Apr 12 '16 at 0:31
  • 3
    Sure, if that was the goal of a C++ compiler. It isn't. Its goal is to hand you the saw with no safety guards and expects you to use it in a way that doesn't cut your hand off. – Robert Harvey Apr 12 '16 at 1:44
  • 1
    The compiler may be able to figure it out and issue a warning or a compilation error. The standard simply doesn't require it to do so. The book's explanation that “the program will simply overwrite whatever is stored in the next memory address past the end of the array” is a likely but by no means the required outcome. See the great answers here for a more detailed discussion. It may also instrument your code to catch the error at run-time, which is what sanitizers do. The C++ standard is flexible enough to permit all of this. – 5gon12eder Apr 12 '16 at 1:58
  • 4
    Compilers aren't stupid in that regard; the C++ language (and the C language on which it's based) is stupid in that regard. This is a well-known problem called "buffer overflow* and it's been a major source of online security holes for literally over a quarter of a century, but a lot of programmers are stupid in that regard, and have failed to abandon C in favor of a less stupidly-insecure language. – Mason Wheeler Apr 12 '16 at 2:04
  • 2
    C++ doesn't check array bounds for the same reason that this car doesn't have seat belts. – Gort the Robot Apr 12 '16 at 2:51
7

Why doesn't the compiler complain? Because it's not required to. The language standard describes the circumstances that require a compiler to complain, and a mere array-index-out-of-bounds is not one of them.

Decent static analysis tools are capable of detecting this scenario for specific cases. The simple case of:

int anArray[25];
anArray[25] = 0;

will likely be detected by most static analysis tools. But C and C++ compilers are not required to do so.

As for why the standard doesn't require them to... why should it?

Your particular scenario is only trivially detectable for two reasons:

  1. The compiler has knowledge of the size of that array.

  2. The index you are using is known by the compiler at compile time.

In real-world cases of index-out-of-bounds scenarios, one or both of these will usually not be true. And no, C++ does not in fact have ways of knowing what the length of an array is. Because you can do this:

int *arr = new int[25];
int *arr2 = arr + 5;

arr2 is just as much of an array as arr. And yet, there is no way to determine how many elements are in arr2.

And even if you could... that wouldn't be something you would know at compile time. Accessing said length would be a runtime memory access. Once the array becomes an int*, it's no longer an array; it's just a pointer, which you can access as though it were an array. The compiler no longer has certain knowledge of what gets stored there. So you've lost #1.

So there is no way that the compiler could complain in most of the real-world cases that are problematic.

The next, unasked, question is why doesn't the compiler emit runtime code to verify things like this? Because such runtime safety takes time, and by default C and C++ are not safe languages. By design, they are intended to achieve the fastest possible performance, even if that means that writing broken (or breakable) code is easier than writing correct code.

You can like it or hate it, applaud it or deride it. However you feel about it, that's the design ethic of the language(s).

  • 1
    There is nothing in the C++ standard, however, that says that a compiler must not emit run-time bounds checking code. And there are compilers that provide options to do that, actually. – 5gon12eder Apr 12 '16 at 4:45
  • 1
    @5gon12eder: I'd be curious to see how you could do runtime bounds checking on a pointer parameter variable which may or may not point to an array. At least, not without breaking ABI compatibility, since most ABIs don't pass an integer size along with pointers. Or, as in the example I provided, where you get a pointer to part of an array. I'm sure there are compilers that can emit code to do some bounds checking. But it would never be comprehensive. – Nicol Bolas Apr 12 '16 at 5:19
  • I'm thinking about the tricks that sanitizers do. Augmenting pointers to know what they point to would be another option. Sure, it would be ABI breaking, but the C++ standard has nothing to say about ABIs as far as I'm aware. I'm not encouraging compilers should do this. Just wanted to mention that reliably aborting the program with an error message would be a perfectly valid response to invoking undefined behavior. – 5gon12eder Apr 12 '16 at 22:04
0

MIT (I think) has some great online courses archived that I've been observing. One of the really cool and powerful things about being able to do this is that you can specifically access memory that you wouldn't normally be allowed to. This offers you all sorts of ways to do things you probably shouldn't. ;)

But I think the main reason that this is possible is that an array variable really only stores the address of the first index. It does not have a way, that I know of, to also store specifically how large the array is. Obviously, somewhere in memory this information existed at some point because an appropriate amount of memory was set aside for the array of a certain size, but for whatever reason this is not easily retrievable.

  • 2
    That's only true for pointers to arrays, or for arrays in C. C++ actually does have a notion of array size; see stackoverflow.com/questions/4108313/… – Robert Harvey Apr 12 '16 at 1:56
  • 2
    This is not "cool and powerful"; it's a massive security hole masquerading as a language feature for 1337 haxx0rz. – Mason Wheeler Apr 12 '16 at 2:05
  • @MasonWheeler But what I'm seeing as being really neat and powerful about it is that you can pass this address pointer to a function which accepts it as a char[] address. You can then parse it out into whatever data type it really is. Whether it's an int[], long int[], or whatever. Send it off as a char[] and search through the memory at your leisure. – Wayman Bell III Apr 12 '16 at 2:09
  • 1
    @WaymanBellIII There are plenty of ways to do that without opening up massive security holes. Civilized languages generally do what you're describing with streams. – Mason Wheeler Apr 12 '16 at 2:10
  • 5
    @MasonWheeler I'd rather not have this discussion go off into a flame war about programming languages. What can be said, though, is that reading data out of random pointers – even if it might appear to work – is undefined behavior in C and C++. If a program relies on this for its proper functioning, it is broken by the standard. – 5gon12eder Apr 12 '16 at 2:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.