Is it possible to predict stack overflow in C on Linux?

There are certain conditions that can cause a stack overflow on an x86 Linux system:

  • struct my_big_object[HUGE_NUMBER] on the stack. Passing through it ultimately causes SIGSEGV .
  • The alloca() routine (for example, malloc() , but uses the stack, automatically frees itself, and also explodes with SIGSEGV if it is too large). Update: alloca () is not officially deprecated, as I originally pointed out; he is just discouraged .

Is there a way to programmatically determine if a local stack is sufficient for a given object? I know that the stack size is configured via ulimit , so I hope there is a way (no matter how it is portable). Ideally, I would like to do something like this:

 int min_stack_space_available = /* ??? */; if (object_size < min_stack_space_available) { char *foo = alloca(object_size); do_stuff(foo); } else { char *foo = malloc(object_size); do_stuff(foo); free(foo); } 
+4
source share
12 answers

You can determine the stack space available to the process by finding the size of the process stack space and then subtracting the amount used.

 ulimit -s 

shows the stack size on linux system. For a programmatic approach, getrlimit () . Then, to determine the current stack depth, subtract the pointer to the top of the stack from one to the bottom. For example (unverified code):

 unsigned char *bottom_of_stack_ptr; void call_function(int argc, char *argv) { unsigned char top_of_stack; unsigned int depth = (&top_of_stack > bottom_of_stack_ptr) ? &top_of_stack-bottom_of_stack_ptr : bottom_of_stack_ptr-&top_of_stack; if( depth+100 < PROGRAMMATICALLY_DETERMINED_STACK_SIZE ) { ... } } int main(int argc, char *argv) { unsigned char bottom_of_stack; bottom_of_stack_ptr = &bottom_of_stack; my_function(); return 0; } 
+4
source

The deprecated alloca () procedure (for example, malloc (), but uses the stack, automatically frees itself, and also explodes SIGSEGV if it is too large).

Why is alloca deprecated?

Anyway, how much faster in your case is alloca vs malloc? (Is it worth it?)

And will it fail to return null from alloca if there is not enough space left? (same as malloc?)

And when your code crashes, where does it crash? is it in alloca or is in doStuff ()?

/ Johan

+1
source

alloca () is going to return NULL on error, I believe that the behavior of alloca (0) is undefined and a variant of the platform. If you check this before do_something (), you should never suffer from SEGV.

I have a couple of questions:

  • Why, why, do you need something big on the stack? The default size for most systems is 8M, which is still too small?
  • If the function that calls alloca () blocks protects the same amount of heap through mlock () / mlockall (), guarantees the same access speed (ie, "Don't change me, bro!") Over time? If you use the more aggressive "rt" scheduler, it is recommended that you call it one way or another.

The question is interesting, but raises an eyebrow. He lifts the needle onto my square pin-round-o-meter.

+1
source

The alloca function is not deprecated. However, this is not in POSIX, and also depends on the machine and the compiler. The Linux man page for alloca notes that β€œfor certain applications, using it can improve performance compared to using malloc, and in some cases it can also make it easier to free memory in applications that use longjmp () or siglongjmp (). Otherwise case, its use is not recommended. "

The manpage also says that "there is no error indicator if the stack frame cannot be expanded. However, after unsuccessful allocation, the program is likely to receive SIGSEGV."

Malloc performance was actually mentioned in Stackoverflow Podcast # 36 .

(I know this is not the correct answer to your question, but I thought it might be useful anyway.)

+1
source

Not sure if this applies to Linux, but on Windows it can lead to access violations with large stack allocations, even if they succeed!

This is due to the fact that, by default, VMM only actually marks the highest (not sure how many) 4096-byte pages of RAM in the form of pages (i.e., it is supported by a page file), since it considers that access to the glass usually will move down from above; as access gets closer and closer to the current β€œborder,” the lower and lower pages are marked as viewable. But this means that reading / writing early memory well below the top of the stack will result in an access violation because that memory has not yet been allocated!

+1
source

You do not say much about why you want to allocate on the stack, but if it is a model of stack memory that is attractive, you can also implement stack allocation on the heap. Allocate a large chunk of memory at the beginning of the program and save a stack of pointers that will correspond to frames in the regular stack. You just need to remember that you are typing your own stack pointer when the function returns.

+1
source

Several compilers, such as Open Watcom C / C ++ , support the stackavail () function, which allows you to do just that.

+1
source

You can use GNU libsigsegv to handle page errors, including cases where a stack overflow occurs (from your website):

In some applications, the handler performs some cleanup or notifies the user, and then immediately terminates the application. In other applications, the handler returns to the center point of the application. This library supports both uses. In the second case, the handler must ensure the restoration of the normal signal mask (since many signals are blocked during the execution of the handler), and sigsegv_leave_handler () must also be called to control the transmission; then only he can leave.

+1
source

Even if this is not a direct answer to your question, I hope you are aware of the existence of valgrind , a great tool for detecting such run-time problems on Linux.

Regarding the stack problem, you can try to allocate objects dynamically from a fixed pool that detects these overflows. With simple macro magic, you can run this run in debug mode, with the actual code running at release time, and therefore know (at least for the scripts you run) that you are not taking too much. Here is additional information and a link to an example implementation.

0
source

Not as good as I can think. Perhaps this is possible using getrlimit () (suggested earlier) and some pointer arithmetic? But first ask yourself if you really want it.

  void * closeToBase;

 main () {
   int closeToBase;
   stackTop = & closeToBase;
 }

 int stackHasRoomFor (int bytes) {
   int currentTop;
   return getrlimit (...) - (& currentTop - closeToBase)> bytes + SomeExtra;
 }

Personally, I would not do that. Allocate large things on the heap, the stack is not designed for this.

0
source

The end of the stack area is determined dynamically by the OS. Although you can find the "static" boundaries of the stack by looking at virtual memory (VMA) areas in a very OS-dependent way (see stackvma * files in libsigsegv / src / ), you will also have to consider

0
source

Sorry if this indicates the obvious, but you can easily write a function to check for a specific stack distribution size by simply trying alloca (of that size) and catching the exception. If you wanted, you could put it in a function with some predefined math for the overhead of the function stack. For instance:

 bool CanFitOnStack( size_t num_bytes ) { int stack_offset_for_function = 4; // <- Determine this try { alloca( num_bytes - stack_offset_for_function ); } catch ( ... ) { return false; } return true; } 
-2
source

All Articles