En programación informática , la comprobación de límites es cualquier método para detectar si una variable se encuentra dentro de ciertos límites antes de su uso. Generalmente se utiliza para asegurar que un número se ajuste a un tipo determinado (comprobación de rango) o que una variable utilizada como índice de un array esté dentro de los límites del array (comprobación de índice). Un fallo en la comprobación de límites suele generar algún tipo de señal de excepción .
Dado que realizar comprobaciones de límites en cada uso puede llevar mucho tiempo, no siempre se lleva a cabo. La eliminación de comprobaciones de límites es una técnica de optimización del compilador que elimina las comprobaciones de límites innecesarias.
Comprobación de rango
Una comprobación de rango confirma que un número se encuentra dentro de un rango válido para el funcionamiento del programa, como por ejemplo, asegurar que un valor que se va a asignar a un entero de 16 bits esté dentro de la capacidad de dicho entero (es decir, comprobar que no haya desbordamiento ). Esto difiere ligeramente de la comprobación de tipo , que confirma que el tipo de dato es apropiado para el sistema de tipos del programa. Otras comprobaciones de rango pueden ser más restrictivas; por ejemplo, una variable que almacena el número de un mes del calendario puede declararse para aceptar solo el rango de 1 a 12.
Ejemplo en Python :
def set_month ( month : int ): if month < 1 or month > 12 : raise ValueError ( "El mes debe estar entre 1 y 12" )Comprobación de índices
La comprobación de índices implica que, en todas las expresiones que indexan un array, el valor del índice se compara con los límites del array (establecidos al definirlo). Si el índice está fuera de los límites, la ejecución se suspende mediante algún tipo de error. Dado que leer o, sobre todo, escribir un valor fuera de los límites de un array puede provocar fallos o bloqueos del programa, o incluso vulnerabilidades de seguridad (véase desbordamiento de búfer ), la comprobación de índices forma parte de muchos lenguajes de programación de alto nivel .
Entre los primeros lenguajes de programación compilados con capacidad de comprobación de índices se encontraban ALGOL 60 , ALGOL 68 y Pascal , así como lenguajes de programación interpretados como BASIC .
Muchos lenguajes de programación, como C , nunca realizan comprobaciones automáticas de límites para aumentar la velocidad. Sin embargo, esto deja sin detectar muchos errores de desplazamiento de uno y desbordamientos de búfer . Muchos programadores creen que estos lenguajes sacrifican demasiado por una ejecución rápida. [ 1 ] En su discurso de aceptación del Premio Turing de 1980 , CAR Hoare describió su experiencia en el diseño de ALGOL 60 , un lenguaje que incluía comprobación de límites, diciendo:
Una consecuencia de este principio es que cada aparición de cada subíndice de cada variable indexada se verificaba en tiempo de ejecución con respecto a los límites superior e inferior declarados del array. Muchos años después, preguntamos a nuestros clientes si deseaban que ofreciéramos la opción de desactivar estas verificaciones en aras de la eficiencia en las ejecuciones de producción. Nos pidieron unánimemente que no lo hiciéramos, pues ya sabían con qué frecuencia se producen errores de subíndice en las ejecuciones de producción, donde no detectarlos podría ser desastroso. Observo con temor y horror que, incluso en 1980, los diseñadores y usuarios de lenguajes no habían aprendido esta lección. En cualquier rama respetable de la ingeniería, no observar precauciones tan elementales habría sido ilegal desde hace mucho tiempo.
Los lenguajes principales que imponen comprobación en tiempo de ejecución incluyen Ada , C# , Haskell , Java , JavaScript , Lisp , PHP , Python , Ruby , Rust y Visual Basic . Los lenguajes D y OCaml tienen comprobación de límites en tiempo de ejecución que se habilita o deshabilita con un interruptor del compilador. En C++, la comprobación en tiempo de ejecución no forma parte del lenguaje, sino de la STL y se habilita con un interruptor del compilador (_GLIBCXX_DEBUG=1 o _LIBCPP_DEBUG=1). C# también admite regiones inseguras : secciones de código que (entre otras cosas) suspenden temporalmente la comprobación de límites para aumentar la eficiencia. Estas son útiles para acelerar pequeños cuellos de botella críticos en tiempo sin sacrificar la seguridad de todo el programa.
El lenguaje de programación JS++ puede analizar si un índice de matriz o una clave de mapa está fuera de los límites en tiempo de compilación utilizando tipos existentes , que son tipos nominales que describen si el índice o la clave están dentro o fuera de los límites y guían la generación de código. Se ha demostrado que los tipos existentes solo añaden 1 ms de sobrecarga a los tiempos de compilación. [ 2 ]
Comprobación de límites de hardware
La seguridad añadida por la comprobación de límites necesariamente cuesta tiempo de CPU si la comprobación se realiza en software; sin embargo, si las comprobaciones pudieran realizarse mediante hardware, entonces la seguridad puede proporcionarse "gratis" sin coste de tiempo de ejecución. Un sistema temprano con comprobación de límites por hardware fue el mainframe ICL 2900 Series anunciado en 1974. [ 3 ] El ordenador VAX tiene una instrucción de ensamblaje INDEX para la comprobación de índices de matrices que toma seis operandos, todos los cuales pueden usar cualquier modo de direccionamiento VAX . El B6500 y ordenadores Burroughs similares realizaban la comprobación de límites mediante hardware, independientemente del lenguaje de programación que se hubiera compilado para producir el código máquina . Un número limitado de CPU posteriores tienen instrucciones especializadas para comprobar límites, por ejemplo, la instrucción CHK2 en la serie Motorola 68000 .
Desde al menos 2005 se han realizado investigaciones sobre métodos para utilizar la unidad de gestión de memoria virtual integrada de x86 para garantizar la seguridad de los accesos a matrices y búferes. [ 4 ] En 2015, Intel proporcionó sus extensiones Intel MPX en su arquitectura de procesador Skylake , que almacena límites en un registro de la CPU y una tabla en memoria. Al menos desde principios de 2017, GCC admite las extensiones MPX.
Véase también
Referencias
- ↑ Cowan, C; Wagle, F; Calton Pu; Beattie, S; Walpole, J (1999). "Desbordamientos de búfer: Ataques y defensas para la vulnerabilidad de la década". Actas de la Conferencia y Exposición de Supervivencia de la Información de DARPA. DISCEX'00 . Vol. 2. págs. 119–129 . doi : 10.1109/DISCEX.2000.821514 . ISBN 978-0-7695-0490-2. S2CID 167759976 .
- ↑ "JS++ 0.9.0: Análisis eficiente en tiempo de compilación de errores fuera de límites – Blog de JS++" . 11 de enero de 2019. Archivado del original el 12 de enero de 2019.
- ↑ JK Buckle (1978). La serie ICL 2900 (PDF) . Serie de Ciencias de la Computación de Macmillan. págs. 17, 77. ISBN 978-0-333-21917-1Archivado del original (PDF) el 20 de abril de 2018. Consultado el 20 de abril de 2018 .
- ↑ Lap-Chung Lam; Tzi-Cker Chiueh (2005). "Checking Array Bound Violation Using Segmentation Hardware". 2005 International Conference on Dependable Systems and Networks (DSN'05) . pp. 388–397 . doi : 10.1109/DSN.2005.25 . ISBN 0-7695-2282-3. S2CID 6278708 .
Enlaces externos
- “ Sobre las ventajas de la arquitectura etiquetada ”, IEEE Transactions on Computers, volumen C-22, número 7, julio de 1973.
- “ The Emperor's Old Clothes Archived 2017-10-02 at the Wayback Machine ”, The 1980 ACM Turing Award Lecture, CACM volumen 24 número 2, febrero de 1981, pp 75–83.
- “ Bcc: Verificación en tiempo de ejecución para programas en C ”, Samuel C. Kendall, Actas de la Conferencia de Verano de USENIX de 1983.
- “ Comprobación de límites para C ”, Richard Jones y Paul Kelly, Imperial College, julio de 1995.
- “ Descripción general de la seguridad de ClearPath Enterprise Servers MCP ”, Unisys, abril de 2006.
- “ Arquitectura virtual segura: un entorno de ejecución seguro para sistemas operativos comerciales ”, John Criswell, Andrew Lenharth, Dinakar Dhurjati, Vikram Adve, SOSP'07, 21.º Simposio ACM sobre Principios de Sistemas Operativos, 2007.
- “ Fail-Safe C ”, Yutaka Oiwa. Implementación del compilador ANSI-C completo con seguridad de memoria. Conferencia ACM SIGPLAN sobre diseño e implementación de lenguajes de programación (PLDI2009), junio de 2009.
- “ desinfectante de direcciones ”, Timur Iskhodzhanov, Alexander Potapenko, Alexey Samsonov, Kostya Serebryany, Evgeniy Stepanov, Dmitriy Vyukov, LLVM Dev Meeting, 18 de noviembre de 2011.
- Biblioteca C segura de API limitadas
- "La biblioteca C segura" . Revista del Dr. Dobb . 20 de febrero de 2009. Archivado del original el 2 de diciembre de 2013. Consultado el 13 de noviembre de 2012 .
- API segura de C: solución concisa para el desbordamiento de búfer, Fundación OWASP, OWASP AppSec, Pekín 2011
- Macros del manual de la biblioteca GNU C++
- Documentación de libc++ 11.0 Modo de depuración
- Errores informáticos
- Matrices