Categories
arrays c++

Accessing an array out of bounds gives no error, why?

227

I am assigning values in a C++ program out of the bounds like this:

#include <iostream>
using namespace std;
int main()
{
    int array[2];
    array[0] = 1;
    array[1] = 2;
    array[3] = 3;
    array[4] = 4;
    cout << array[3] << endl;
    cout << array[4] << endl;
    return 0;
}

The program prints 3 and 4. It should not be possible. I am using g++ 4.3.3

Here is compile and run command

$ g++ -W -Wall errorRange.cpp -o errorRange
$ ./errorRange
3
4

Only when assigning array[3000]=3000 does it give me a segmentation fault.

If gcc doesn’t check for array bounds, how can I be sure if my program is correct, as it can lead to some serious issues later?

I replaced the above code with

vector<int> vint(2);
vint[0] = 0;
vint[1] = 1;
vint[2] = 2;
vint[5] = 5;
cout << vint[2] << endl;
cout << vint[5] << endl;

and this one also produces no error.

24

  • 3

    Related question: stackoverflow.com/questions/671703/…

    – TSomKes

    Aug 6, 2009 at 16:15

  • 20

    The code is buggy, of course, but it generates undefined behavior. Undefined means it may or may not run to completion. There is no guarantee of a crash.

    Aug 6, 2009 at 16:17

  • 4

    You can be sure your program is correct by not screwing around with raw arrays. C++ programmers should use container classes instead, except in embedded/OS programming. Read this for reasons to user containers. parashift.com/c++-faq-lite/containers.html

    – jkeys

    Aug 6, 2009 at 16:25

  • 11

    Bear in mind that vectors do not necessarily range-check using []. Using .at() does the same thing as [] but does range-check.

    Aug 6, 2009 at 16:31

  • 4

    A vector does not auto-resize when accessing out-of-bounds elements! It’s just U.B.!

    Aug 6, 2009 at 17:02

456

Welcome to every C/C++ programmer’s bestest friend: Undefined Behavior.

There is a lot that is not specified by the language standard, for a variety of reasons. This is one of them.

In general, whenever you encounter undefined behavior, anything might happen. The application may crash, it may freeze, it may eject your CD-ROM drive or make demons come out of your nose. It may format your harddrive or email all your porn to your grandmother.

It may even, if you are really unlucky, appear to work correctly.

The language simply says what should happen if you access the elements within the bounds of an array. It is left undefined what happens if you go out of bounds. It might seem to work today, on your compiler, but it is not legal C or C++, and there is no guarantee that it’ll still work the next time you run the program. Or that it hasn’t overwritten essential data even now, and you just haven’t encountered the problems, that it is going to cause — yet.

As for why there is no bounds checking, there are a couple aspects to the answer:

  • An array is a leftover from C. C arrays are about as primitive as you can get. Just a sequence of elements with contiguous addresses. There is no bounds checking because it is simply exposing raw memory. Implementing a robust bounds-checking mechanism would have been almost impossible in C.
  • In C++, bounds-checking is possible on class types. But an array is still the plain old C-compatible one. It is not a class. Further, C++ is also built on another rule which makes bounds-checking non-ideal. The C++ guiding principle is “you don’t pay for what you don’t use”. If your code is correct, you don’t need bounds-checking, and you shouldn’t be forced to pay for the overhead of runtime bounds-checking.
  • So C++ offers the std::vector class template, which allows both. operator[] is designed to be efficient. The language standard does not require that it performs bounds checking (although it does not forbid it either). A vector also has the at() member function which is guaranteed to perform bounds-checking. So in C++, you get the best of both worlds if you use a vector. You get array-like performance without bounds-checking, and you get the ability to use bounds-checked access when you want it.

14

  • 5

    @Jaif : we have been using this array thing for so long, but still why are there no test to check such simple error ?

    Aug 6, 2009 at 16:40

  • 12

    C++ design principle was that it shouldn’t be slower than the equivalent C code, and C doesn’t do array bound checking. C design principle was basically speed as it was aimed for system programming. Array bound checking takes time, and so is not done. For most uses in C++, you should be using a container rather than array anyway, and you can have your choice of bound check or no bound check by either accessing an element via .at() or [] respectively.

    – KTC

    Aug 6, 2009 at 16:47

  • 4

    @seg Such a check costs something. If you write correct code, you don’t want to pay that price. Having said that, I’ve become a complete convert to std::vector’s at() method, which IS checked. Using it has exxposed quite a few errors in what I thought was “correct” code.

    – anon

    Aug 6, 2009 at 16:48

  • 11

    I believe old versions of GCC actually launched Emacs and an a simulation of Towers of Hanoi in it, when it encountered certain types of undefined behavior. Like I said, anything may happen. 😉

    – jalf

    Aug 6, 2009 at 17:18

  • 5

    Everythings already been said, so this only warrants a small addendum. Debug builds can be very forgiving in these circumstances when compared to release builds. Due to debug information being included in debug binaries, there’s less of a chance that something vital is overwritten. That’s sometimes why the debug builds seem to work fine whilst the release build crash.

    – Rich

    Aug 6, 2009 at 18:02

39

Using g++, you can add the command line option: -fstack-protector-all.

On your example it resulted in the following:

> g++ -o t -fstack-protector-all t.cc
> ./t
3
4
/bin/bash: line 1: 15450 Segmentation fault      ./t

It doesn’t really help you find or solve the problem, but at least the segfault will let you know that something is wrong.

4

  • 12

    I just found even a better option: -fmudflap

    – Hi-Angel

    Dec 24, 2014 at 8:00

  • 4

    @Hi-Angel: Modern equivalent is -fsanitize=address which catches this bug both at compile time (if optimizing) and at runtime.

    Jul 15, 2020 at 14:10


  • 2

    @NateEldredge +1, nowadays I even use -fsanitize=undefined,address. But it’s worth noting that there are rare corner cases with std library, when out of bounds access is not detected by sanitizer. For this reason I’d recommend to additionally use -D_GLIBCXX_DEBUG option, which adds even more checks.

    – Hi-Angel

    Jul 15, 2020 at 15:23

  • 2

    Thank you Hi-Angel. when -fmudflap and -fsanitize=address didn’t work for me, -fsanitize=undefined,address found not only a function that wasn’t returning an value, it also found the array assignment that was happening out of bounds.

    – Nav

    Nov 30, 2020 at 8:18

15

g++ does not check for array bounds, and you may be overwriting something with 3,4 but nothing really important, if you try with higher numbers you’ll get a crash.

You are just overwriting parts of the stack that are not used, you could continue till you reach the end of the allocated space for the stack and it’d crash eventually

EDIT:
You have no way of dealing with that, maybe a static code analyzer could reveal those failures, but that’s too simple, you may have similar(but more complex) failures undetected even for static analyzers

1

  • 7

    Where do you get if from that at the address of array[3] and array[4], there is “nothing really important”??

    – namezero

    Sep 9, 2013 at 10:08