Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting that the stack is full

When writing C++ code I've learned that using the stack to store memory is a good idea.

But recently I ran into a problem:

I had an experiment that had code that looked like this:

void fun(const unsigned int N) {
    float data_1[N*N];
    float data_2[N*N];

    /* Do magic */
}

The code exploted with a seqmentation fault at random, and I had no idea why.

It turned out that problem was that I was trying to store things that were to big on my stack, is there a way of detecting this? Or at least detecting that it has gone wrong?

like image 805
Martin Kristiansen Avatar asked Jun 18 '12 09:06

Martin Kristiansen


People also ask

How do I know if my stack is full?

void push (int stack[ ] , int x , int n) { if ( top == n-1 ) { //if top position is the last of position of stack, means stack is full .

How do you detect stack overflow?

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 happens if stack memory is full?

When the stack fills up, you get a StackOverflowException exception. Of course the stack may fill up, if your code has a bug which causes runaway recursion, or if you use recursion to implement an algorithm which is unsuitable for recursion, like for example linear search.

How is stack underflow detected?

Stack Underflow & Overflow Stack underflow happens when we try to pop (remove) an item from the stack, when nothing is actually there to remove. This will raise an alarm of sorts in the computer because we told it to do something that cannot be done.


2 Answers

float data_1[N*N];
float data_2[N*N];

These are variable length arrays (VLA), as N is not a constant expression. The const-ness in the parameter only ensures that N is read-only. It doesn't tell the compiler that N is constant expression.

VLAs are allowed in C99 only; in other version of C, and all versions of C++ they're not allowed. However, some compilers provides VLA as compiler-extension feature. If you're compiling with GCC, then try using -pedantic option, it will tell you it is not allowed.

Now why your program gives segfault, probably because of stack-overflow due to large value of N * N:


Consider using std::vector as:

#include <vector> 

void fun(const unsigned int N) 
{
  std::vector<float> data_1(N*N);
  std::vector<float> data_2(N*N);

  //your code
}
like image 188
Nawaz Avatar answered Sep 19 '22 05:09

Nawaz


It's extremely difficult to detect that the stack is full, and not at all portable. One of the biggest problems is that stack frames are of variable size (especially when using variable-length arrays, which are really just a more standard way of doing what people were doing before with alloca()) so you can't use simple proxies like the number of stack frames.

One of the simplest methods that is mostly portable is to put a variable (probably of type char so that a pointer to it is a char*) at a known depth on the stack and to then measure the distance from that point to a variable (of the same type) in the current stack frame by simple pointer arithmetic. Add in an estimate of how much space you're about to allocate, and you can have a good guess as to wether the stack is about to blow up on you. The problems with this are that you don't know the direction that the stack is growing in (no, they don't all grow in the same direction!) and working out the size of the stack space is itself rather messy (you can try things like system limits, but they're really quite awkward). Plus the hack factor is very high.

The other trick I've seen used on 32-bit Windows only was to try to alloca() sufficient space and handle the system exception that would occur if there was insufficient room.

int have_enough_stack_space(void) {
    int enough_space = 0;

    __try {           /* Yes, that's got a double-underscore. */
        alloca(SOME_VALUE_THAT_MEANS_ENOUGH_SPACE);
        enough_space = 1;
    }  __except (EXCEPTION_EXECUTE_HANDLER) {}

    return enough_space;
}

This code is very non-portable (e.g., don't count on it working on 64-bit Windows) and building with older gcc requires some nasty inline assembler instead! Structured exception handling (which this is a use of) is amongst the blackest of black arts on Windows. (And don't return from inside the __try construct.)

like image 41
Donal Fellows Avatar answered Sep 18 '22 05:09

Donal Fellows