¿Cuál es la línea de código más peligrosa en C++?

código más peligrosa en C++ es esta:


  1. Fred[8472] = 8743872; 



Esto parece inofensivo, pero si Fred fue definido para tener, digamos, 8000 elementos, entonces esa línea de código va a intentar escribir el integer 8743872 en alguna ubicación desconocida de la RAM. Y lo que resulte de eso podría ser casi cualquier cosa.
Si tienes suerte, el sistema operativo (o el propio programa) reconocerá que se ha producido un intento de acceso ilegal a la memoria, e imprimirá un mensaje de error en tu pantalla y tu programa terminará.
Si no tienes suerte, el número entero puede escribirse encima del código que luego se ejecuta, y podría suceder casi cualquier cosa. El código espurio podría dañar archivos críticos del sistema operativo, o enviar un correo electrónico a tu esposa con fotos tuyas teniendo una aventura con una amante, o inscribirte en un campo de entrenamiento de terroristas suicidas de Al Qaeda, o iniciar la Tercera Guerra Mundial, o transmitir por radio un horrible insulto a una nave espacial que esta pasando cerca de la tierra llena de alienígenas hostiles (que luego destruyen la Tierra), o lo que sea. Oh, Dios mío.
Así que no hagas eso. Si crees que debes usar matrices en C o C++, siempre revisa cuidadosamente los límites. Y hagas lo que hagas, no escribas programas como este:


  1. // over-run-test-cpp.cpp 




  2. #include <stdio.h> 




  3. int main (void) 








  4. int Fred[505] = {0}; 




  5. Fred[634] = 87592; 




  6. printf("Fred[634] = %dn", Fred[634]); 




  7. return 0; 







En mi sistema, incluso con banderas de advertencia fuertes, mi compilador (gcc / g++) compila eso sin errores ni advertencias! Y funciona sin errores ni advertencias, y da el resultado deseado! Pero el código fuente está cometiendo acceso ilegal a la memoria y ordenando la sobre-escritura de la memoria que en realidad no posee!

Entonces, ¿por qué eso no causó una advertencia del compilador y/o un error en tiempo de ejecución? ¡Por la optimización! El compilador, viendo que ni siquiera estoy cerca de llenar el array, cambia silenciosamente el índice del “87592” de “634” a “0”.
¡¡¡PERO!!! ¿Y si alguien altera el programa años después? Los cambios pueden tener consecuencias devastadoras que el compilador no podrá optimizar:


  1. // evil-test-2.cpp 




  2. #include <cstdio> 




  3. int main (void) 








  4. int Fred[500]; 




  5. int i; 




  6. for ( i = 0 ; i < 100000 ; ++i ) 








  7. Fred[i] = i; 




  8. } printf("Fred[34927] = %dn", Fred[34927]); 




  9. return 0; 







String de compilación:


  1. g++ -I /rhe/include -D PLATFORM_IS_WIN64 -Wall -Wextra -Wfloat-equal -Wshadow -Wcast-qual -Wcast-align -Wconversion -Wcomments -Wundef -Wunused-macros -Wold-style-cast -Woverloaded-virtual -finput-charset=UTF-8 -std=gnu++14 -s -O2 evil-test-2.cpp -L/rhe/lib64 -L/lib -L/usr/lib -lm -o /rhe/bin64/test/evil-test-2.exe 



Las advertencias del compilador emite:


  1. evil-test-2.cpp: In function ‘int main()’: 




  2. evil-test-2.cpp:9:15: warning: iteration 500 invokes undefined behavior [-Waggressive-loop-optimizations] 




  3. Fred[i] = i; 




  4. ~~~~~~~~^~~ 




  5. evil-test-2.cpp:7:20: note: within this loop 




  6. for ( i = 0 ; i < 100000 ; ++i ) 




  7. ~~^~~~~~~~ 




  8. evil-test-2.cpp:11:10: warning: array subscript is above array bounds [-Warray-bounds] 




  9. printf("Fred[34927] = %dn", Fred[34927]); ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 



Resultados en tiempo de ejecución:


  1. $ evil-test-2 




  2. Segmentation fault (core dumped) 



Esta vez el compilador no fue capaz de optimizar los problemas, y todo explotó.
Así que, ¡no cuenten con que siempre puedan salirse con la suya con un código desprolijo! ¡En ningún lenguaje de programación! Es posible que puedas salirte con la tuya a corto plazo por varias razones (como que la optimización del compilador te arregle los errores, como en el ejemplo anterior), pero a largo plazo, volverá y te morderá, y de muy mala manera (caídas de programas, caídas del sistema, daños en el hardware, pérdida de datos, pérdidas financieras, bancarrota de la empresa, terminación del empleo, falta de vivienda, o algo peor). ¡Así que no lo hagas!
En el lenguaje de programación C++, específicamente, no deberías usar arrays o punteros en absoluto, excepto cuando sea absolutamente necesario, y sólo si sabes lo que estás haciendo y estás haciendo una cuidadosa y frecuente comprobación de los límites. En vez de eso, usa los “containers”, “iteradores” y “algoritmos” proporcionados por “The Standard Template Library” (“STL” para abreviar). La STL existe para ser usada, y si estás escribiendo en C++ deberías usarla intensamente. Específicamente, usa su plantilla “vector” para la mayoría de las cosas para las que usarías matrices en C. Y usa el método “.at()” en objetos vectores, en lugar de [corchetes], para invocar la comprobación automática de límites.

Deja un comentario