tags:

views:

6391

answers:

8

I'm using MinGW with GCC 3.4.5 (mingw-special vista r3).

My C application uses a lot of stack so I was wondering is there any way I can tell programatically how much stack is remaining so I can cleanly handle the situation if I find that I'm about to run out.

If not what other ways would you work around the problem of potentially running out of stack space?

I've no idea what size of stack I'll start with so would need to identify that programatically also.

A: 

Assuming you know the size of the full stack you could probably add some assembly code to read ESP.
If you read ESP and save it aside in the main function you can compare the current ESP to the ESP you have in main and see how much ESP has changed. That'll give you an indication of how much stack you're used.

Nathan Fellman
+3  A: 

Taking the address of a local variable off the stack would work. Then in a more nested call you can subtract the address of another local to find the difference between them

size_t top_of_stack;

void Main()
{
  int x=0;
  top_of_stack = (size_t) &x;

  do_something_very_recursive(....)
}

size_t SizeOfStack()
{
  int x=0;
  return top_of_stack - (size_t) &x;
}

If you code is multi-threaded then you need to deal with storing the top_of_stack variable on a per-thread basis.

Rob Walker
I like this answer but without knowing the size of stack up front I've got no way of telling if I'm about to blow it up.
Paul Hargreaves
There will be a default size of the stack for threads on your system. In Windows this is 1MB of address space. You can control this if you are creating your own threads. Though as Skizz points out it would be best not to have to worry about the exact limit!
Rob Walker
This might be fine on MinGW in particular. In general, the stack for a program is not guaranteed to be contiguous. It's legal for an implementation (one which doesn't have virtual memory, for example) to allocate stack blocks as required and chain them together. Of course if your platform does that, then there might not even be a default max stack size for a program: you could just keep going until you run out of free memory. But a good reason to have a limit anyway is to prevent runaway recursion from taking down the whole system by exhausting memory.
Steve Jessop
+5  A: 

Raymond Chen (The Old New Thing) has a good answer to this sort of question:

If you have to ask, you're probably doing something wrong.

Here's some Win32 details on stack allocation: link to MSDN.

If you think you might be limited by stack space, you will almost certainly be limited by available virtual memory, in which case, you will need to find a different solution.

What exactly are you trying to do?

Skizz

Skizz
A (not great) example would be:void subroutine(int i) { char foo[20000]; i++; if (i < 1000) subroutine(i);}
Paul Hargreaves
You're right, that's not a good example. What I really wanted to know was what you were doing with the 20k array.
Skizz
Although if you've ever tried to write really, truly portable code, you learn that "you always have to ask, and you're always doing something wrong, because there is no portable concept of "stack usage" and yet it's the programmer's responsibility not to use too much stack. So it's best just to join the conspiracy of silence, write a functional test that you hope consumes as much stack as your program ever will in practice, and leave it to the platform integrator to worry about".
Steve Jessop
A: 

This is a problem I have given up on. With a lot of hacking and (mostly) praying, you can get a solution that works at a given time on a given machine. But in general there seems to be no decent way to do this.

You will have to obtain the stack position and size from outside your program (on Linux you might get it from /proc/<pid>/maps). In your program you must somehow test where you are at the stack. Using local variables is possible, but there is no real guarantee that they are actually on the stack. You can also try to get the value from the stack pointer register with some assembly.

So now you have the location of the stack, its size and the current position and you assume you know in which direction the stack grows. When are you going in stack-overflow mode? You better not do it close to the end because your estimation (i.e. address of local variable or value from stack pointer) is probably a bit too optimistic; it's not uncommon to address memory beyond the stack pointer. Also, you have no clue about how much room on the stack any given function (and the functions it calls) need. So you'll have to leave quite some room at the end.

I can only advice you not do get into this mess and try to avoid very deep recursion. You might also want to increase your stack size; on Windows you have to compile this into the executable, I believe.

mweerden
+1  A: 

check if your compiler supports stackavail()

dmityugov
A: 

There's a problem if your stack is auto-increasing. You can have a situation where if the current stack runs out of space the system automatically increases its size. At which point you can't detect the size of the stack; only that you've run out of stack space.

I think the most reliable thing to do here is trap memory allocation exceptions when allocating an array of such size. Either that or allocate from the heep. A 20,000 element array on the stack is not a good idea.

Peter Ritchie
+2  A: 

Hello,

maybe this will help for Windows platform only:

in the PE header (IMAGE_NT_HEADERS) of your exe there are some records such as:


typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    ...
}

There is a simple way to obtain these values: using GetModuleHandle(NULL) will give you the imagebase (handle) of your module, address where you'll find a IMAGE_DOS_HEADER structure which will help you to find the IMAGE_NT_HEADERS structure (imagebase+IMAGE_DOS_HEADER.e_lfanew) -> IMAGE_NT_HEADERS, and there you'll find those fields: SizeOfStackReserve and SizeOfStackCommit.

The maximum amount of space that the OS will allocate for your stack is SizeOfStackReserve.

If you consider trying this, let me know and I will assist you. There is a way to obtain the size of stack used in a certain point.

botismarius
A: 

On Linux, you would call getrusage and check the returned struct rusage's ru_isrss member (integral unshared stack size).

From the MINGW site and its sourceforge site's tracking of patches, I see that in May of 2008 there was some patching done around getrusage and it looks like it's been generally supported for quite a while. You should check carefully for any caveats in terms of how much of the typical Linux functionality is supported by MinGW.

Thomas Kammeyer