Question

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.

Was it helpful?

Solution

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: 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?

OTHER TIPS

The getrusage function gets you the current usage . (see man getrusage).

The getrlimit in Linux would help fetching the stack size with the RLIMIT_STACK parameter.

#include <sys/resource.h>
int main (void)
{
  struct rlimit limit;

  getrlimit (RLIMIT_STACK, &limit);
  printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max);
}

Please give a look at man getrlimit. The same information could be fetched by ulimit -s or ulimit -a stack size row. Also have a look at setrlimit function which would allow to set the limits. But as the mentioned in the other answers if you need to adjust stack then probably you should re consider your design. If you want a big array why not take the memory from the heap ?

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.

check if your compiler supports stackavail()

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.

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.

For windows: I've done this before using the VirtualQuery function from Kernel32.dll. I only have an example in C# but it demonstrates the technique:

public static class StackManagement
    {
        [StructLayout(LayoutKind.Sequential)]
        struct MEMORY_BASIC_INFORMATION
        {
            public UIntPtr BaseAddress;
            public UIntPtr AllocationBase;
            public uint AllocationProtect;
            public UIntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        };

        private const long STACK_RESERVED_SPACE = 4096 * 16;

        public unsafe static bool CheckForSufficientStack(UInt64 bytes)
        {
            MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
            UIntPtr currentAddr = new UIntPtr(&stackInfo);
            VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

            UInt64 stackBytesLeft = currentAddr.ToUInt64() - stackInfo.AllocationBase.ToUInt64();

            return stackBytesLeft > (bytes + STACK_RESERVED_SPACE);
        }

        [DllImport("kernel32.dll")]
        private static extern int VirtualQuery(UIntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
    }

BTW: This code can also be found on StackOverflow on another question which I asked when I was trying to fix a bug in the code: Arithmetic operation resulted in an overflow in unsafe C#enter link description here

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top