Question

Please tell me the difference between stack and heap with respect to below code

int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
    arr [3000] = 8 ; //SIGSEGV 

    a = malloc (sizeof (int));
    a[4] = 6; 
    a[4000] = 8; //No error
}

I know that arr is a static array and I am accessing some other process's address when I do arr[3000] which gives SIGSEGV error. But I don't understand why a[4000] will not give me any run time error i.e., SIGSEGV signal.

Thanks

Was it helpful?

Solution

It's not guaranteed that any of those calls actually write to inaccessible memory (which would trigger a segfault). It's just as likely that the program has permission to write to that memory and doesn't trigger a segfault, but overwrites some other internal data unrelated to your array. This of course might lead to unexpected effects elsewhere in the program.

Generally this is called undefined behavior. There are no promises made what happens when you write out of the bounds of the array, anything might or might not happen.

OTHER TIPS

Referencing the items outside the array bounds is undefined behavior, which means anything could happen (exception, no exception, or other). The reason the arr[5] assignment did not cause an error is probably because the value was still inside valid stack space (but it could result in errors later on in a longer running application). The invalid assignment to the allocated array may have resulted in a write to a page in memory belonging to the process and thus not result in an error. But that could change from run to run. And even if the address belonged to a page outside the process' address space, it depends on the OS on what will actually happen.

Heap is the memory from which you malloc() the block of memory from.

a[4000] = 8; didn't fail because it was a luck that it didn't fall into memory address of other process. It was just by chance

All cases that you highlighted represent 'undefined behavior'.

And in some cases it's a noop, and in others it's a segmentation fault.

What's particularly bad about 'undefined behavior' is that it may work as expected for some time, but then suddenly start producing "undesirable side effects" ( i.e. segmentation faults ). This makes it very difficult to debug and reproduce these conditions in production.

int main()
{
    int arr[3];
    int *a;

    arr [5] = 6; // out of bound but it will not give error.
// J: False - it is undefined. expect raptors, or something.

    arr [3000] = 8 ; //SEGSEV
// J: Now you see the effects of undefined behavior, even though you did not in a previous invalid access.

    a = malloc (sizeof (int));
    a[4] = 6; // J: Still undefined behavior
    a[4000] = 8; //No error
// J: Still undefined behavior
}

But i dont understand why a[4000] will not give me any run time error ie,. segsev signal.

It will on another platform or architecture. This really doesn't matter - you must always avoid UB.

At any rate, the difference is in the implementation of your system's allocator (assuming the compiler did not place the result of malloc on the stack).

How your allocator manages and distributes memory is an implementation detail you should not rely on, especially when you're throwing UB around.

An allocator can vend pieces of memory from a larger physical allocation. This underlying implementation varies by platform.

Buffer overflows are undefined behavior. A buffer overflow can crash on Monday if it is on stack and crash on Tuedsay if it is on heap. They are just undefined behavior.

Here is the C paragraph that says it is undefined behavior:

(C99, 6.5.6p8) "If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated."

And of course a [] is a disguised unary * operator:

(6.5.2.1p2) "The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))."

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top