c integer-overflow

¿Se puede desbordar argc?



integer-overflow (4)

Estaba vagando en SO y vi esta pregunta . Entonces comencé a preguntarme si puedo desbordar argc.

Standard dice que argv[argc] debe ser un puntero nulo, pero esto será falso si se desborda argc.

( wrote un pequeño programa en C y un script de Python para probarlo pero obtuve un MemoryError ).

¡Gracias!

Justificación de la norma internacional - Lenguajes de programación - C §5.1.2.2.1 Inicio del programa

La especificación de argc y argv como argumentos para main reconoce una práctica previa extensa. Se requiere que argv[argc] sea ​​un puntero nulo para proporcionar una verificación redundante para el final de la lista, también sobre la base de la práctica común.


De acuerdo a la norma

Entonces, de tu cita:

Se requiere argv[argc] para ser un puntero nulo

Por lo tanto, argc no puede desbordarse, porque la afirmación anterior no sería verdadera.

En la práctica

En la práctica, el tamaño total de los argumentos pasados ​​a un programa es limitado.

En mi sistema Linux / x64:

$ getconf ARG_MAX 2097152

Por lo tanto, el tamaño total del argumento es de aproximadamente 2 megabytes, y argc no puede desbordarse. Creo que este límite mide una combinación de los datos totales en argv y el entorno. Si excede este límite cuando intenta ejecutar un comando, exec() fallará con E2BIG . Del man 2 execve :

E2BIG The total number of bytes in the environment (envp) and argument list (argv) is too large.

Creo que el límite de ~ 2 megabytes en mi sistema es relativamente generoso en comparación con otros sistemas. Mi sistema OS X informa un límite de ~ 260 KB.

Pero, ¿y si ARG_MAX fuera realmente grande?

De acuerdo, supongamos que está en un sistema antiguo / extraño, por lo que int tiene 16 bits y ARG_MAX tiene más de 2 15 , lo que es bastante razonable. Ahora, suponga que invoca execve() con más de 2 15 argumentos. La implementación tiene dos opciones.

  1. Puede permitir que se desborde argc ... básicamente, desechando sus datos, asegurando que el programa que está ejecutando se ejecute de manera inesperada y probablemente errónea, y violando el estándar C. Lo peor de todo, el error es silencioso, por lo que es posible que nunca sepas.

  2. O simplemente puede devolver EOVERFLOW de execve() , informándole que simplemente no puede ejecutar una imagen con tantos parámetros. Ahora, los estándares POSIX / SUS no mencionan nada acerca de este resultado de error ... pero, sospecho que esto es simplemente porque los escritores estándar nunca esperaron que ARG_MAX fuera más grande que INT_MAX .

La opción # 2 es la única opción razonable. Si su sistema de alguna manera elige la opción # 1, entonces está roto y debe presentar un informe de error.

Alternativamente, podría estar intentando ejecutar un programa antiguo compilado para un sistema de 16 bits, pero lo está ejecutando a través de algún tipo de emulador o capa de compatibilidad. Esperaría que el emulador o la capa de compatibilidad emitieran un mensaje de error si intentara pasar más de 2 15 parámetros a un programa.


Como lo indica el estándar, argv [argc] debe ser un valor válido.

Entonces, si el entorno de tiempo de ejecución se encuentra en una situación tal que no puede garantizarlo, no debe iniciar el programa.


En la práctica, no, no puedes. La mayoría de los sistemas establecen un límite relativamente bajo en el tamaño combinado total de argv y envp . Los límites en las decenas a bajos cientos de KB no son infrecuentes; ver http://www.in-ulm.de/~mascheck/various/argmax/ para obtener una lista razonablemente completa de los límites en varios sistemas operativos.


Intenté esto:

prueba.c:

⚡⚡⚡ more test.c #include <stdio.h> int main(int argc, char **argv) { printf("argc = %d/n", argc); printf("Size of argc = %d/n", sizeof(argc)); return 0; }

Luego usó un gran archivo zip

⚡⚡⚡ ls -h bigfile -rw-r--r-- 1 ehwas ehwas 355M Jan 22 16:54 bigfile

Luego lea el archivo como parámetros para el programa de prueba:

⚡⚡⚡ ./test $(more bigfile)

Resultado:

5 minutes nothing happend, then everything froze

Luego probé un archivo más pequeño:

⚡⚡⚡ ls -h notsobigfile -rw-r--r-- 1 ehwas ehwas 6.7M Jan 22 17:04 notsobigfile

Y:

⚡⚡⚡ ./test $(more notsobigfile) bash: ./test: Argument list too long