Search code examples
cpointersmemorystackbuffer-overflow

Accessing variable after an array by trying to access a position greater than its dimension in C


Since in this example I'm able to read value of integer2 thanks to pointer arithmetic:

#include <stdio.h>

    int main() {
      int integer1 = 1;
      int integer2 = 2;
      int *p = &integer1;
      p++;
      printf("%d\n", *p);
    } 

with output:

$ ./test
2

I was wondering why in this example:

#include <stdio.h>

int main()
{
  int array[2] = {0, 1};
  int variable = 0;
  for(int i = 0; i < 3; i++) {
    printf("%d\n", array[i]);
  }
}

then I'm not able to read the value of variable trying to point the next integer but that's what I get:

0
1
336859392

I tried printing the values of &array[0] &array[1] and &variable and this is what I got:

161695488
161695492
161695480

Not only the address of variable is less than the one of the first elements of the array, but it's not even the previous one.
Why in the first example variables address are contiguous and in the second one not?
There is probably something I don't understand on how variables and buffers are allocated in the stack.

EDIT: I know this should not be done, but I'm trying to understand buffer overflows (more realistically the buffer should be of character, given as input by an user), and the goal should be to alter the value of the variable. So what I'm trying to understand is if it's possible to know exactly where the variable actually is in memory.

EDIT2: Turns out that giving -fno-stack-protector makes it work as expected, so gcc is adding by default some sort of protection in order to avoid buffer overflows


Solution

  • The placement of local variables is a detail of the implementation. They may be placed in any order it deems appropriate.

    Attempting to read past the bounds of an array invokes undefined behavior. The inconsistent results you see are a manifestation of that.

    As an example, if I run your first code snippet, I do not get 2 as the output. When printing the addresses of each variable, I get:

    &integer1=0x7ffcfa6e8c24, &integer2=0x7ffcfa6e8c20
    

    So in my case the implementation puts integer1 after integer2.