Comprobación del uso de la pila en tiempo de compilación


¿Hay una manera de conocer y generar el tamaño de pila necesario para una función en tiempo de compilación en C ? Esto es lo que me gustaría saber :

Tomemos alguna función:

void foo(int a) {
    char c[5];
    char * s;
    //do something
    return;
}

Al compilar esta función, me gustaría saber cuánto espacio de pila consumirá cuando se llame. Esto podría ser útil para detectar la declaración on stack de una estructura que oculta un búfer grande.

Estoy buscando algo que imprima algo como esto:

Archivo foo.c : el uso de la pila de función foo es n bytes

¿Hay alguna manera de no mirar el ensamblado generado para saber eso ? ¿O un límite que se puede establecer para el compilador ?

Actualización : No estoy tratando de evitar el desbordamiento de pila de tiempo de ejecución para un proceso dado, estoy buscando una manera de encontrar antes del tiempo de ejecución, si un uso de pila de funciones, según lo determinado por el compilador, está disponible como salida del proceso de compilación.

Pongámoslo de otra manera: ¿es posible saber el tamaño de todos los objetos locales a una función ? Supongo que la optimización del compilador no será mi amiga, porque alguna variable desaparecerá, pero un límite superior está bien.

Author: Björn Lindqvist, 2008-09-24

7 answers

El código del kernel de Linux se ejecuta en una pila 4K en x86. Por eso les importa. Lo que utilizan para comprobar que, es un script de perl que escribieron, que puede encontrar como scripts/checkstack.pl en un tarball reciente del kernel (2.6.25 lo tiene). Se ejecuta en la salida de objdump, la documentación de uso está en el comentario inicial.

Creo que ya lo usé para binarios de espacio de usuario hace mucho tiempo, y si sabes un poco de programación perl, es fácil arreglarlo si está roto.

De todos modos, lo que básicamente hace es para mirar automáticamente la salida de GCC. Y el hecho de que los hackers del kernel escribieran tal herramienta significa que no hay una forma estática de hacerlo con GCC (o tal vez que se agregó muy recientemente, pero lo dudo).

Por cierto, con objdump del proyecto mingw y ActivePerl, o con Cygwin, debería poder hacerlo también en Windows y también en binarios obtenidos con otros compiladores.

 10
Author: Blaisorblade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-12 08:59:27

StackAnlyser parece examinar el código ejecutable en sí más información de depuración. Lo que describe esta respuesta, es lo que estoy buscando, stack analyzer me parece exagerado.

Algo similar a lo que existe para ADA estaría bien. Mira esta página del manual del gnat:

22.2 Análisis del Uso de la Pila Estática

Una unidad compilada con-fstack-usage generará un archivo adicional que especifica la cantidad máxima de pila utilizada, en un base por función. El archivo tiene el mismo nombre de base que el archivo objeto de destino con una extensión. su. Cada línea de este archivo se compone de tres campos:

* The name of the function.
* A number of bytes.
* One or more qualifiers: static, dynamic, bounded. 

El segundo campo corresponde al tamaño de la parte conocida del marco de la función.

El calificador static significa que el tamaño del marco de la función es puramente estático. Normalmente significa que todas las variables locales tienen un tamaño estático. En este caso, el segundo campo es una medida confiable de la pila de funciones utilización.

El calificador dinámico significa que el tamaño del marco de la función no es estático. Sucede principalmente cuando algunas variables locales tienen un tamaño dinámico. Cuando este calificador aparece solo, el segundo campo no es una medida confiable del análisis de pila de funciones. Cuando se califica con acotado, significa que el segundo campo es un máximo confiable de la utilización de la pila de funciones.

 8
Author: shodanex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:00:12

No veo por qué un análisis de código estático no podría dar una cifra lo suficientemente buena para esto.

Es trivial encontrar todas las variables locales en cualquier función dada, y el tamaño de cada variable se puede encontrar ya sea a través del estándar C (para tipos incorporados) o calculándolo (para tipos complejos como estructuras y uniones).

Claro, no se puede garantizar que la respuesta sea 100% precisa, ya que el compilador puede hacer varios tipos de optimizaciones como relleno, poniendo variables en registros o eliminar completamente variables innecesarias. Pero cualquier respuesta que dé debería ser una buena estimación al menos.

Hice una búsqueda rápida en Google y encontré StackAnalyzer pero mi conjetura es que otras herramientas de análisis de código estático tienen capacidades similares.

Si desea una cifra 100% precisa, entonces tendría que mirar la salida del compilador o comprobarla durante el tiempo de ejecución (como Ralph sugirió en su respuesta)

 3
Author: Isak Savo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:10

Solo el compilador lo sabría realmente, ya que es el tipo que pone todas tus cosas juntas. Tendría que mirar el ensamblado generado y ver cuánto espacio está reservado en el preámbulo, pero eso realmente no explica cosas como alloca que hacen lo suyo en tiempo de ejecución.

 1
Author: 1800 INFORMATION,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 08:34:48

Asumiendo que estás en una plataforma embebida, podrías encontrar que tu cadena de herramientas tiene una oportunidad en esto. Los buenos compiladores comerciales integrados (como, por ejemplo, el compilador Arm/Keil) a menudo producen informes del uso de la pila.

Por supuesto, las interrupciones y la recursión suelen estar un poco más allá de ellas, pero te da una idea aproximada si alguien ha cometido algún error terrible con un búfer de varios megabytes en la pila en algún lugar.

 1
Author: Will Dean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 11:03:48

No es exactamente "tiempo de compilación", pero haría esto como un paso posterior a la compilación:

  • deje que el enlazador cree un archivo de mapa para usted
  • para cada función en el archivo de mapa, lea la parte correspondiente del ejecutable y analice el prólogo de la función.

Esto es similar a lo que hace StackAnalyzer, pero mucho más simple. Creo que analizar el ejecutable o el desmontaje es la forma más fácil de llegar a la salida del compilador. Mientras que el compilador sabe esas cosas internamente, yo me temo que no podrá obtenerlo de él (puede pedirle al proveedor del compilador que implemente la funcionalidad, o si usa el compilador de código abierto, podría hacerlo usted mismo o dejar que alguien lo haga por usted).

Para implementar esto necesitas:

  • ser capaz de analizar el archivo de mapa
  • comprender el formato del ejecutable
  • saber cómo puede ser un prólogo de función y ser capaz de "decodificarlo"

Qué tan fácil o difícil sería esto depende de su objetivo plataforma. (Incrustado? ¿Qué arquitectura de CPU? Qué compilador?)

Todo esto definitivamente se puede hacer en x86/Win32, pero si nunca hiciste nada como esto y tienes que crear todo esto desde cero, puede tomar unos días antes de que haya terminado y tener algo funcionando.

 1
Author: Suma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-18 21:55:30

No en general. El Problema de la detención en la informática teórica sugiere que ni siquiera se puede predecir si un programa general se detiene en una entrada dada. Calcular la pila utilizada para ejecutar un programa en general sería aún más complicado. Entonces: no. Tal vez en casos especiales.

Digamos que tiene una función recursiva cuyo nivel de recursión depende de la entrada que puede ser de longitud arbitraria y ya está fuera de suerte.

 -1
Author: xmjx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 09:43:05