Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting stack overflows during runtime beforehand

I have a rather huge recursive function (also, I write in C), and while I have no doubt that the scenario where stack overflow happens is extremely unlikely, it is still possible. What I wonder is whether you can detect if stack is going to get overflown within a few iterations, so you can do an emergency stop without crashing the program.

like image 874
J. Rickson Avatar asked Feb 05 '16 11:02

J. Rickson


People also ask

How are stack overflows detected?

A method of detecting stack overflows is to create a canary space at the end of each task. This space is filled with some known data. If this data is ever modified, then the application has written past the end of the stack.

What should I do if the stack memory overflowed?

If your mobile device's operating system is giving you a stack overflow error, you may have too many applications running, a virus uses stack space, or your device has bad hardware. Check your app usage and virus protection and run a memory diagnostic app on your mobile device to see if this helps clear up your error.

How can we detect possible potential stack overflow problems in ac C++ program?

One way to retrieve the exact location of the stack is to look at the file /proc/1234/maps (where 1234 is the process ID of your program). Once you know these bounds you can compute how much of your stack is used by looking at the address of the latest local variable.

What is a stack overflow and how is it prevented?

A stack overflow is a type of buffer overflow error that occurs when a computer program tries to use more memory space in the call stack than has been allocated to that stack.


2 Answers

In the C programming language itself, that is not possible. In general, you can't know easily that you ran out of stack before running out. I recommend you to instead place a configurable hard limit on the recursion depth in your implementation, so you can simply abort when the depth is exceeded. You could also rewrite your algorithm to use an auxillary data structure instead of using the stack through recursion, this gives you greater flexibility to detect an out-of-memory condition; malloc() tells you when it fails.

However, you can get something similar with a procedure like this on UNIX-like systems:

  1. Use setrlimit to set a soft stack limit lower than the hard stack limit
  2. Establish signal handlers for both SIGSEGV and SIGBUS to get notified of stack overflows. Some operating systems produce SIGSEGV for these, others SIGBUS.
  3. If you get such a signal and determine that it comes from a stack overflow, raise the soft stack limit with setrlimit and set a global variable to identify that this occured. Make the variable volatile so the optimizer doesn't foil your plains.
  4. In your code, at each recursion step, check if this variable is set. If it is, abort.

This may not work everywhere and required platform specific code to find out that the signal came from a stack overflow. Not all systems (notably, early 68000 systems) can continue normal processing after getting a SIGSEGV or SIGBUS.

A similar approach was used by the Bourne shell for memory allocation.

like image 174
fuz Avatar answered Oct 02 '22 21:10

fuz


Heres a simple solution that works for win-32. Actually resembles what Wossname already posted but less icky :)

unsigned int get_stack_address( void )
{
    unsigned int r = 0;
    __asm mov dword ptr [r], esp;
    return r;
}
void rec( int x, const unsigned int begin_address )
{
    // here just put 100 000 bytes of memory
    if ( begin_address - get_stack_address() > 100000 )
    {
        //std::cout << "Recursion level " << x << " stack too high" << std::endl;
        return;
    }
    rec( x + 1, begin_address );
}
int main( void )
{
    int x = 0;
    rec(x,get_stack_address());
}
like image 28
mainactual Avatar answered Oct 02 '22 22:10

mainactual