¿El sistema operativo reserva la cantidad fija de espacio virtual válido para la pila o algo más? ¿Puedo producir un desbordamiento de pila simplemente usando grandes variables locales?
He escrito un pequeño Cprograma para probar mi suposición. Se ejecuta en X86-64 CentOS 6.5.
#include <string.h>
#include <stdio.h>
int main()
{
int n = 10240 * 1024;
char a[n];
memset(a, 'x', n);
printf("%x\n%x\n", &a[0], &a[n-1]);
getchar();
return 0;
}
Ejecutar el programa da &a[0] = f0ceabe0y&a[n-1] = f16eabdf
Los mapas de proceso muestran la pila: 7ffff0cea000-7ffff16ec000. (10248 * 1024B)
Entonces traté de aumentar n = 11240 * 1024
Ejecutar el programa da &a[0] = b6b36690y&a[n-1] = b763068f
Los mapas de proceso muestran la pila: 7fffb6b35000-7fffb7633000. (11256 * 1024B)
ulimit -simprime 10240en mi PC.
Como puede ver, en ambos casos el tamaño de la pila es mayor de lo que ulimit -sda. Y la pila crece con una variable local más grande. La parte superior de la pila está de alguna manera 3-5kB más apagada &a[0](AFAIK la zona roja es 128B).
Entonces, ¿cómo se asigna este mapa de pila?
fuente

ulimit -s10240, como en las condiciones del OP, y obtengo un SIGSEGV como se esperaba (esto es lo que requiere POSIX: "Si se excede este límite, se generará SIGSEGV para el hilo. "). Sospecho que hay un error en el núcleo del OP.Kernel de Linux 4.2
rlim[RLIMIT_STACK]que corresponde al POSIXgerlimit(RLIMIT_STACK)acct_stack_growthPrograma de prueba mínima
Luego podemos probarlo con un programa NASM mínimo de 64 bits:
Asegúrese de desactivar ASLR y eliminar las variables de entorno, ya que irán a la pila y ocuparán espacio:
El límite está en algún lugar ligeramente por debajo de mi
ulimit -s(8MiB para mí). Parece que esto se debe a los datos adicionales especificados por el Sistema V inicialmente colocados en la pila además del entorno: parámetros de la línea de comandos de Linux 64 en Ensamblado | Desbordamiento de pilaSi se toma esto en serio, TODO crea una imagen inicial mínima que comienza a escribir desde la parte superior de la pila y baja, y luego ejecútela con QEMU + GDB . Coloque un
dprintfbucle que imprima la dirección de la pila y un punto de interrupción enacct_stack_growth. Será gloriosoRelacionado:
fuente
De forma predeterminada, el tamaño máximo de la pila está configurado para ser de 8 MB por proceso,
pero se puede cambiar usando
ulimit:Mostrando el valor predeterminado en kB:
Establecer en ilimitado:
ulimit -s unlimitedafectando el shell actual y los subshells y sus procesos secundarios.
(
ulimites un comando integrado de shell)Puede mostrar el rango real de direcciones de pila en uso con:
cat /proc/$PID/maps | grep -F '[stack]'en Linux.
fuente
ulimit -sKB sea válido para el programa. En mi caso son 10240 KB. Pero cuando declaro un conjuntochar a[10240*1024]y conjunto locala[0]=1, el programa sale correctamente. ¿Por qué?int n = 10240*1024; char a[n]; memset(a,'x',n);... seg culpa.a[]no se ha asignado en su pila de 10 MB. El compilador podría haber visto que no podía haber una llamada recursiva y había hecho una asignación especial, o algo más, como una pila discontinua o alguna indirección.