6

Okay, so I was teaching my girlfriend some c++, and she wrote a program that I thought wouldn't work, but it did. It accesses one more element in the array then there is (for instance, accessing array[5] for an array of size 5). Is this an instance of a buffer overflow? My thoughts on it are that it's writing to/accessing the memory directly after the array, is this correct? Basically my question here is..why does this work?

#include <iostream>

using namespace std;

int main()
{
int size;

cout << "Please enter a size for the array." << endl;
cin >> size;
cout << endl;

cout << "There are " << size << " elements in this array." << endl;
cout << endl;
cout << endl;
cout << endl;

int array[size];

for (int counter = 1; counter <= size; counter++)

{
    cout << "Please enter a value for element " << counter << "." << endl;
    cin >> array[counter];

}

cout << endl;
cout << endl;


for (int counter = 1; counter <= size; counter++)

{
    cout << "Element " << counter << " is " << array[counter] << "." << endl;
    cout << endl;

}

cout << "*bing! :)" << endl;
cout << endl;


return 0;
}
dlev
  • 48,024
  • 5
  • 125
  • 132
Nathan
  • 73,987
  • 14
  • 40
  • 69

5 Answers5

24

It's undefined behavior. UB comes in many flavors. Here are a few:

1) It will kick your dog.

2) It will reformat your hard drive.

3) It will work without a problem.

In your case, with your compiler and on your platform and on this particular day, you are seeing (3). But try it elsewhere, and you might get (1), (2), or something else completely (most likely an access violation).

Jim Buck
  • 20,482
  • 11
  • 57
  • 74
7

C/C++ does not do boundary checking when using arrays.

Since you are declaring a stack based array. Accessing outside the bounds of the array will just access another part of already allocated stack space.

So basically when you access something that is out of bounds, it won't throw a segmentation fault unless its completely out of your stack memory.

C/C++ is dangerous with array boundaries remember that!

Kevin
  • 3,509
  • 4
  • 31
  • 45
  • I am a little curious about the memory layout of the stack with that dynamically-sized variable on it. On my laptop (i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)) gdb's "print (char*)&size - (char*)&array[size]" says something like 84 or 96 (depending on what I enter as size). I'm not sure what's between them. valgrind doesn't even spot the error. I disassembled the function but the assembly was more complicated than I was hoping for. – Scott Lamb Apr 07 '12 at 05:14
2

The stack is very large. On Windows, it's 1 MB.

Since the program doesn't do much, the array would have been allocated close to the beginning of the stack. This means there would be almost 1 MB of empty space between the end of the array and the end of the stack.

So what does this mean? When you write past the end of the array, you're just clobbering your own stack space, not other programs', so the OS doesn't stop you and the program continues to run.

Lambda Fairy
  • 13,814
  • 7
  • 42
  • 68
  • 1
    Stack grows down, so the empty portion is off the beginning of the array, not the end. Otherwise correct. – Ben Voigt Nov 01 '14 at 18:25
  • Yes, in VS2013,I once declared an array `int a[65535]`,and until for `a[i]`, `i == 84330`,the program throws an exception. – Yuan Wen May 10 '16 at 00:39
0

Firstly, array sizes need to be constant so

 int arr[size] 

will not work as size is a variable, so, either fix the size of the array at compile time or use dynamic memory allocation.

i.e. either

  const int size =5; 
  int arr[size];

or

  int arr[5];

or

  int* arr = new int[5];

AND..

Taking a pointer to one element beyond the end of array is guaranteed to work in C++. This is important for many algorithms provided by the STL. However, since such a pointer does not infact point to an element of the aray, it may not be used for reading and writing. On the other hand, the result of taking the address of the element before the initial element is undefined and should be avoided..

i.e. you can take the address of that variable and then come back but can't use it!!!

bhuwansahni
  • 1,834
  • 1
  • 14
  • 20
  • what? Taking an elements beyond the array is not guaranteed to work (segmentation faults). In addition Size is of type int thats just saying int size = 5; int arr[5]. This answer is pretty wrong. – Kevin Apr 07 '12 at 04:50
  • 2
    Variable-length arrays are a feature of C which was implemented as an extension in many C++ compilers. `int arr[size];` is valid C99. – dreamlax Apr 07 '12 at 04:57
  • @Kevn, you can take the address of an element just beyond the end of the array, but you can't dereference that address (http://stackoverflow.com/questions/1021021/c-element-beyond-the-end-of-an-array). Not really relevant for this question, however. – Keith Randall Apr 07 '12 at 05:02
  • That is what i mean, you can move your pointer to one element beyond the array but can't read or write it!! Size needs to be a constant means either const int size =5; int arr[size]; or int arr[5]; – bhuwansahni Apr 07 '12 at 05:50
0

Here, you know that array index starts from 0 and goto 5

You input your counter as 5 which starts from 1 and goto 5

You are using index 1 for counter 1 ,index 2 for couter 2, and so on .

Index 0 still have no input value and contain garbage value.

IndieProgrammer
  • 579
  • 1
  • 5
  • 14