tags:

views:

285

answers:

8

Why infinite recursion leads to seg fault ? Why stack overflow leads to seg fault. I am looking for detailed explanation.

int f()                                                                                                                                                      
{                                                                                                                                                            
  f();                                                                                                                                                       
}                                                                                                                                                            

int main()                                                                                                                                                   
{                                                                                                                                                            
  f();                                                                                                                                                       
}                                                                                                    
+12  A: 

Every time you call f(), you increase the size of the stack - that's where the return address is stored so the program knows where to go to when f() completes. As you never exit f(), the stack is going to increase by at least one return address each call. Once the stack segment is full up, you get a segfault error. You'll get similar results in every OS.

Skizz
Except for compilers that optimise tail calls into loop. But you answer is correct anyway, +1 from me
qrdl
+2  A: 

AFAIK: The ends of the stack are protected by addresses that aren't accessible to the process. This prevents the stack from growing over allocated data-structures, and is more efficient than checking the stack size explicitly, since you have to check the memory protection anyway.

Douglas Leeder
This makes sense
Pqr
+6  A: 

Segmentation fault is a condition when your program tries to access a memory location that it is not allowed to access. Infinite recursion causes your stack to grow. And grow. And grow. Eventually it will grow to a point when it will spill into an area of memory that your program is forbidden to access by the operating system. That's when you get the segmentation fault.

Dima
I'd say this is the best answer..
Jeriko
+1  A: 

It's still a stackoverflow ;-)

The thing is that the C runtime doesn't provide "instrumentalisation" like other managed languages do (e.g. Java, Python, etc.), so writing outside the space designated for the stack instead of causing a detailed exception just raises a lower level error, that has the generic name of "segmentation fault".

This is for performance reasons, as those memory access watchdogs can be set with help of hardware support with little or none overhead; I cannot remember the exact details now, but it's usually done by marking the MMU page tables or with the mostly obsolete segment offsets registers.

fortran
A: 

It's essentially the same principle as a buffer overflow; the OS allocates a fixed amount of memory for the stack, and when you run out (stack overflow) you get undefined behavior, which in this context means a SIGSEGV.

The basic idea:

int stack[A_LOT];
int rsp=0;

void call(Func_p fn)
    {
    stack[rsp++] = rip;
    rip = fn;
    }

void retn()
    {
    rip = stack[--rsp];
    }

/*recurse*/
for(;;){call(somefunc);}

eventually rsp moves past the end of the stack and you try to put the next return address in unallocated storage and your program barfs. Obviously real systems are a lot more complicated than that, but that could (and has) take up several large books.

David X
A: 

At a "low" level, the stack is "maintained" through a pointer (the stack pointer), kept in a processor register. This register points to memory, since stack is memory after all. When you push values on the stack, its "value" is decremented (stack pointer moves from higher addresses to lower addresses). Each time you enter a function some space is "taken" from the stack (local variables); moreover, on many architectures the call to a subroutine pushes the return value on the stack (and if the processor has no a special register stack pointer, likely a "normal" register is used for the purpose, since stack is useful even where subroutines can be called with other mechanisms), so that the stack is at least diminuished by the size of a pointer (say, 4 or 8 bytes).

In an infinite recursion loop, in the best case only the return value causes the stack to be decremented... until it points to a memory that can't be accessed by the program. And you see the segmentation fault problem.

You may find interesting this page.

ShinTakezou
some RISC architectures store the return address in a register... but this does not allow for recursion, nor to call another subroutines, unless it allows to use different registers; since registers are usually limited, at the end one would use what is more conveniente to allow recursion... i.e. a stack... or some other mechanisms (like MMIX) that however consumes memory, which can be addressed someway, and so the same problem arises soon or later.
ShinTakezou
A: 

A program copunter or instruction pointer is a register which contains the value of next instruction to be executed. In a function call, the current value of program counter pushed into the stack and then program counter points to first instruction of the function. The old value is poped after returning from that function and assigned to program counter. In infinite recursion the value is pushed again and again and leads to the stack overflow.

Shrikant
+2  A: 

Your system resources are finite. They are limited. Even if your system has the most memory and storage on the entire Earth, infinite is WAY BIGGER than what you have. Remember that now.

The only way to do something an "infinite number of times" is to "forget" previous information. That is, you have to "forget" what has been done before. Otherwise you have to remember what happened before and that takes storage of one form or another (cache, memory, disk space, writing things down on paper, ...)--this is inescapable. If you are storing things, you have a finite amount of space available. Recall, that infinite is WAY BIGGER than what you have. If you try to store an infinite amount of information, you WILL run out of storage space.

When you employ recursion, you are implicitly storing previous information with each recursive call. Thus, at some point you will exhaust your storage if you try to do this an infinite number of takes. Your storage space in this case is the stack. The stack is a piece of finite memory. When you use it all up and try to access beyond what you have, the system will generate an exception which may ultimately result in a seg fault if the memory it tried to access was write-protected. If it was not write-protected, it will keep on going, overwriting god-knows-what until such time as it either tries to write to memory that just does not exist, or it tries to write to some other piece of write protected memory, or until it corrupts your code (in memory).

Sparky