Question

I have written two small programs in which I declare a very small array.

Then I try to access values out of bounds.

The interesting thing I noticed that when I try to decrement the index I can decrement this very very further away. If I try to increment it the program crashes much faster.

This is my two codes and the results:

 #include<stdio.h>
 int main()
 {
     int i=0;                                                                
     int a[2];

     while(1)
     {
         a[-10000]=8;
         printf("i is: %d and the value a[i] is: %d\n",i,a[i]);
         i--;

      }

      return 0;
 }

The final lines of the result are:

i is: -3143957 the value of a[i] is: 0 i is: -3143958 the value of a[i] is: 0 i is: -3143959 the value of a[i] is: 0 i is: -3143960 the value of a[i] is: 0 i is: -3143961 the value of a[i] is: 0 i is: -3143962 the value of a[i] is: 0 i is: -3143963 the value of a[i] is: 0 i is: -3143964 the value of a[i] is: 0 Segmentation fault

However when I try to increment the index i

 #include<stdio.h>
 int main()
 {
     int i=0;                                                                
     int a[2];

     while(1)
     {
         a[-10000]=8;
         printf("i is: %d and the value a[i] is: %d\n",i,a[i]);
         i++;

      }

      return 0;
 }

I get the following result: i is: 2306 and the value a[i] is: 1869098813 i is: 2307 and the value a[i] is: 1764713837 i is: 2308 and the value a[i] is: 1634624869 i is: 2309 and the value a[i] is: 795175011 i is: 2310 and the value a[i] is: 1802724676 i is: 2311 and the value a[i] is: 7368564 i is: 2312 and the value a[i] is: 778121006 i is: 2313 and the value a[i] is: 7632239 i is: 2314 and the value a[i] is: 0 i is: 2315 and the value a[i] is: 0

The difference between how much I can go UP and how much I can go DOWN is HUGE. Why is that.

Some things to mention: I KNOW that this is undefined behavior. My question is strictly about WHY can I go much much further UP vs DOWN when going OUT OF BOUNDS of an array.

Was it helpful?

Solution

It is mostly coincidence that you can read more garbage by decrementing than incrementing.

What's likely happening is that the compiler has put the address of a[0] on the stack. The compiler will also have reserved some memory for the stack in general and probably put a guard page after that memory to catch stack overflows.

What I suspect is happening when you decrement is that you're walking along the reserved stack memory until you hit the guard page and seg faulting.

Now, the compiler will have reserved some global memory for various things in the runtime above the stack. What I suspect is happening when you increment is that it is walking that memory until it hits another page fault on memory that it can't read. It is likely that it reserved less global memory than it did stack memory hence it can increment less than it can decrement.

You can experiment with this. For example, by putting a large array on the stack before the int a[2] declaration, you should be able to walk that extra memory on increment before it barfs. If that doesn't work (it might not as the compiler can re-order the variables on the stack within a function) then having the large array in main and putting the stack walk loop in a function called by main should do the trick.

Note, however, this is all largely supposition without knowing details about the machine, OS and compiler. For example, I am assuming that the stack grows downwards which isn't universally true.

BTW not sure why you have the statement a[-10000]=8; but it's probably not doing what you think it's doing. Specifically, the compiler will, almost definitely be able to establish statically that this is UB and, being UB, could choose to do just about anything with it; complete removal being the most likely.

Licensed under: CC-BY-SA with attribution
scroll top