Verificando el tamaño de stack disponible en C

Estoy usando MinGW con GCC 3.4.5 (mingw-especial vista r3).

Mi aplicación C usa mucha stack, así que me pregunto si hay alguna forma de que pueda determinar de manera programática cuánto queda de stack para poder manejar la situación de forma limpia si descubro que estoy a punto de terminar.

Si no, ¿de qué otra forma trabajarías para resolver el problema de la posibilidad de quedarte sin espacio en la stack?

No tengo idea del tamaño de la stack con la que comenzaré, así que también debería identificarla programáticamente.

Raymond Chen ( The Old New Thing ) tiene una buena respuesta a este tipo de preguntas:

Si tiene que preguntar, probablemente esté haciendo algo mal.

Aquí hay algunos detalles de Win32 sobre la asignación de la stack: MSDN .

Si cree que puede estar limitado por el espacio de la stack, es casi seguro que estará limitado por la memoria virtual disponible, en cuyo caso, tendrá que encontrar una solución diferente.

¿Qué estás tratando de hacer exactamente?

La función getrusage te proporciona el uso actual. (ver man getrusage ).

El getrlimit en Linux ayudaría a recuperar el tamaño de la stack con el parámetro RLIMIT_STACK .

 #include  int main (void) { struct rlimit limit; getrlimit (RLIMIT_STACK, &limit); printf ("\nStack Limit = %ld and %ld max\n", limit.rlim_cur, limit.rlim_max); } 

Por favor, eche un vistazo a man getrlimit . La misma información podría ser obtenida por ulimit -s o ulimit -a fila de tamaño de stack. También eche un vistazo a la función setrlimit que permitiría establecer los límites. Pero como se menciona en las otras respuestas, si necesita ajustar la stack, entonces probablemente debería reconsiderar su diseño. Si quieres una gran matriz ¿por qué no tomar la memoria del montón?

Quitar la dirección de una variable local de la stack funcionaría. Luego, en una llamada más anidada, puede restar la dirección de otro local para encontrar la diferencia entre ellos

 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; } 

Si su código es de subprocesos múltiples, debe ocuparse de almacenar la variable top_of_stack por subproceso.

comprueba si tu comstackdor es compatible con stackavail ()

Suponiendo que conozca el tamaño de la stack completa, probablemente pueda agregar algún código de ensamblaje para leer ESP.
Si lee ESP y lo guarda en la función principal, puede comparar el ESP actual con el ESP que tiene en main y ver cuánto ha cambiado el ESP. Eso te dará una indicación de cuánta stack estás utilizando.

Para Windows: he hecho esto antes de usar la función VirtualQuery de Kernel32.dll. Solo tengo un ejemplo en C # pero demuestra la técnica:

 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); } 

Por cierto: Este código también se puede encontrar en StackOverflow en otra pregunta que hice cuando estaba tratando de corregir un error en el código: operación aritmética resultó en un desbordamiento en inseguro C # ingrese la descripción del enlace aquí

Este es un problema que he abandonado. Con una gran cantidad de piratería y (principalmente) rezando, puede obtener una solución que funcione en un momento dado en una máquina determinada. Pero, en general, parece que no hay una forma decente para hacer esto.

Deberá obtener la posición y el tamaño de la stack fuera de su progtwig (en Linux puede obtenerlo de /proc//maps ). En tu progtwig debes probar de alguna manera dónde estás en la stack. Usar variables locales es posible, pero no hay una garantía real de que estén realmente en la stack. También puede intentar obtener el valor del registro del puntero de la stack con algún ensamblaje.

Entonces ahora tienes la ubicación de la stack, su tamaño y la posición actual, y supones que sabes en qué dirección crece la stack. ¿Cuándo vas en modo desbordamiento de stack? Es mejor que no lo haga cerca del final porque su estimación (es decir, la dirección de la variable local o el valor del puntero de la stack) es probablemente demasiado optimista; no es raro dirigir la memoria más allá del puntero de la stack. Además, no tiene ni idea de cuánto espacio en la stack necesita una función determinada (y las funciones que llama). Así que tendrás que dejar bastante espacio al final.

Solo puedo aconsejarte que no entres en este lío e intentes evitar recursiones muy profundas. También es posible que desee boost el tamaño de su stack; en Windows, tienes que comstackr esto en el ejecutable, creo.

tal vez esto ayude solo para la plataforma de Windows:

en el encabezado PE (IMAGE_NT_HEADERS) de su exe hay algunos registros como:


 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;
     ...
 }

Hay una manera simple de obtener estos valores: el uso de GetModuleHandle (NULL) le dará la base de datos (identificador) de su módulo, dirección donde encontrará una estructura IMAGE_DOS_HEADER que le ayudará a encontrar la estructura IMAGE_NT_HEADERS (imagebase + IMAGE_DOS_HEADER. e_lfanew) -> IMAGE_NT_HEADERS, y allí encontrará los campos: SizeOfStackReserve y SizeOfStackCommit .

La cantidad máxima de espacio que el sistema operativo asignará a su stack es SizeOfStackReserve.

Si consideras intentar esto, házmelo saber y te ayudaré. Hay una manera de obtener el tamaño de la stack utilizada en un cierto punto.

En Linux, debe llamar a getrusage y verificar el miembro ru_isrss de struct rusage devuelto (tamaño de stack no compartida integral).

Desde el sitio de MINGW y el seguimiento de parches realizado por el sitio de sourceforge, veo que en mayo de 2008 se realizaron algunos parches en torno a getrusage y parece que en general se admitió durante bastante tiempo. Debe comprobar cuidadosamente si hay alguna advertencia en cuanto a qué parte de la funcionalidad típica de Linux es compatible con MinGW.