Checking available stack size in C

2019-01-02 20:50发布

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.

标签: c stack mingw
9条回答
笑指拈花
2楼-- · 2019-01-02 21:07

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?

查看更多
孤独寂梦人
3楼-- · 2019-01-02 21:11

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

查看更多
泛滥B
4楼-- · 2019-01-02 21:16

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 ?

查看更多
其实,你不懂
5楼-- · 2019-01-02 21:16

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.

查看更多
千与千寻千般痛.
6楼-- · 2019-01-02 21:16

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.

查看更多
冷夜・残月
7楼-- · 2019-01-02 21:19

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.

查看更多
登录 后发表回答