Error de software
# Error de software

Un error de software, error o simplemente fallo (también conocido por el inglés, bug) es un problema en un programa de computadora o sistema de software que desencadena un resultado indeseado. Los programas que ayudan a la detección y eliminación de errores de software son denominados depuradores (en inglés: debuggers).

Entre las numerosas incidencias notables causadas por este tipo de error están la máquina de radioterapia Therac-25 en la década de 1980, la destrucción de la sonda espacial Mariner 1 en 1962, del Ariane 5 501 en 1996, y el Airbus A400M en 2015. También fueron famosos los incidentes de la red de AT&T en 1990, o los accidentes del Boeing 737 MAX en 2018 y 2019 que llevaron a la suspensión de sus vuelos durante meses por fallos en el software MCAS.

En 2002 un estudio encargado por el Instituto Nacional de Estándares y Tecnología del Departamento de Comercio de Estados Unidos concluyó que los errores informáticos costaban a la economía estadounidense 59 500 millones de USD al año, un 0.6% del PIB.

## Orígenes del término

El 9 de septiembre de 1947, la física y matemática Grace Murray Hopper y otros que trabajaban en la Universidad de Harvard en el Mark II informaron de que el ordenador sufrió un fallo en el relé electromagnético #70 del panel F. Cuando se investigó ese relé, el equipo encontró una polilla (bug) electrificada que provocó que el relé quedase abierto. Hopper pegó el insecto con cinta adhesiva en la bitácora con el comentario:

Este incidente es erróneamente referido como el origen de la utilización del término inglés bug («bicho») para indicar un problema en un aparato o sistema. En realidad, el término bug ya formaba parte del idioma inglés, al menos desde que Thomas Alva Edison lo utilizó en sus notas en 1872, en una carta en 1878 para referirse a defectos mecánicos o eléctricos, y en 1889 refiriéndose a interferencias y mal funcionamiento en un fonógrafo. Es posible que Hopper lo haya asociado por primera vez a la informática, en este caso, relacionado con un insecto real. Por otra parte, aunque durante los años 50 del siglo XX, Hopper también empleó en inglés el término debug al hablar de la depuración de errores en los códigos de programación. El primer uso registrado del término se encuentra en la Journal of the Royal Aeronautical Society de 1945:

## Errores de programación comunes

* División por cero
* Ciclo infinito
* Problemas aritméticos como desbordamientos (overflow) o subdesbordamientos (underflow).
* Exceder el tamaño del array definido
* Utilizar una variable no inicializada
* Errores tipográficos varios, por ejemplo confundir el dígito "0" con la vocal "O", confundir el dígito "1" con la letras "I" o "l", o escribir "," en lugar de "." como parte de nombres de variables en lenguajes donde no es necesario declarar las variables antes de usarlas. Por ejemplo, en Fortran IV los espacios no cuentan, por lo que cambiar una coma por un punto en un bucle DO 100 I=1. 10 equivale a la asignación DO100I = 1.10 que por ser una instrucción válida no la reporta el compilador.
* Usar constantes mágicas, es decir que en lugar de definir una variable o macro para definir un parámetro que puede cambiar, poner el valor en el código. Por ejemplo, declarar un arreglo float X[10] y usarla en bucles for i=0 to 10 en varias partes del programa en lugar de definir una constante XSize=10; float X[XSize]; y usar for i=0 to XSize, con lo que se evitan omisiones cuando se cambie la dimensión de X, ya que basta con con cambiar XSize=20 en lugar de buscar en todo el código las constantes mágicas 10 para cambiarlas por 20.
* Acceder a memoria no permitida (Violación de acceso)
* Pérdida de memoria (memory leak)
* Desbordamiento o subdesbordamiento de la pila (estructura de datos) (Stack overflow)
* Desbordamiento de búfer (buffer overflow)
* Bloqueo mutuo (deadlock)
* Indizado inadecuado de tablas en bases de datos.
* Corrupción de las bases de datos relacionales por no estar normalizadas.
* Desbordamiento de la pila de recursión, cuando se dejan demasiadas llamadas en espera.
* Programar por ensayo y error, en lugar de desarrollar los programas sistemáticamente.
* No atender los mensajes de advertencia al momento de compilar un programa.
* Errores que resultan del uso indiscriminado de variables de alcance global.
* Errores por no declarar el tipo de las variables.
* Errores que emergen porque el programador no toma en cuenta la semántica del lenguaje de programación. Por ejemplo, desconocer si el alcance es léxico o dinámico.
* Errores de sintaxis, por ejemplo, no terminar una instrucción con un punto y coma ( ; ) en un lenguaje de programación que lo requiere.
* No documentar correctamente el programa, provoca el no entender qué hace, lo que acarrea errores por no tener claro lo que hace.
* Condición de carrera (race condition)
* Uso incorrecto de API.
* Incompatibilidad de sistemas.

## Defectos de instalación o programación

* Eliminación o sustitución de bibliotecas comunes a más de un programa o del sistema (DLL Hell).
* Reiniciar arbitrariamente la sesión de un usuario para que la instalación tenga efecto.
* Suponer que el usuario tiene una conexión permanente a internet.
* Utilizar como fuente enlaces simbólicos a ficheros que pueden cambiar de ubicación.

## Códigos de errores de lenguajes de programación

La mayor parte de los lenguajes de programación presentan al menos dos tipos de errores que permiten a los programadores manejar las fallas de los programas de una manera eficiente y que no resulte agresiva con el usuario final. Dichos errores son de compilación y errores en tiempo de ejecución.

Los errores de compilación normalmente inhiben que el código fuente derive en un programa ejecutable, mientras que los errores en tiempo de ejecución son situaciones específicas en las que un evento externo al programa impide su ejecución. Regularmente un programador eficiente debe intentar imaginar como debe responder ante esos eventos de manera que sea el programa y no el usuario o el sistema operativo los que resuelvan el problema. Por ejemplo, un bloque de error no manejado podría hacer lo siguiente:

Si "miarchivo" no existe (o el programa o el usuario no tienen privilegios suficientes para abrirlo), el sistema operativo regresará un error que el programa no atrapará y tendremos un mensaje como "El archivo "miarchivo" no puede ser abierto para escritura" y botones para reintentar, cancelar y abortar (en el sistema operativo Windows), que no tendrán otra acción que repetirse indefinidamente sin posibilidad de salir de ese ciclo como no sea dando por terminado violentamente el programa. Un código que permitiese atrapar el error en tiempo de ejecución sería:

Los diferentes lenguajes de programación permiten diferentes construcciones lógicas a los programadores para atrapar y resolver errores en tiempo de ejecución, como pueden ser las sentencias assert, try y on error en diferentes lenguajes de programación.

## Defectos de diseño de programas

* Diseños con colores inapropiados para las personas que padecen daltonismo
* Diseños que usan textos con tipografías de difícil lectura por su tamaño o diseño
* Diseños que fuerzan el uso del ratón sin dejar alternativas de teclado para personas con disfunciones motrices
* Estimar que el equipo donde se instalará tiene determinadas características (como la resolución de la pantalla, la velocidad del procesador, la cantidad de memoria o conectividad a Internet) propias de un equipo de gama alta, en vez de diseñar el software para su ejecución en equipos normales

## Implicaciones

El tipo y cantidad de daño producido por un error de software puede afectar los procesos de toma de decisión y la política sobre la calidad del software. En aplicaciones para el viaje espacial tripulado y para el automóvil los controles de calidad del software deben ser superiores.

## Casos notables

### Y2K

El problema del año 2000 (Y2K) pudo llegar a ser un colapso económico porque muchos programas interpretarían el año 2000 como si fuera el año 1900. Los trabajos de adaptación y corrección de programas evitaron problemas graves.

### Knight Capital

Disrupción de la bolsa de Nueva York en 2012. El 1 de agosto de 2012 Knight Capital provocó una disrupción del mercado de bolsa que le llevó a perder en dos días el 75% de su capitalización bursátil. Knight Capital disponía del software SMARS que gestionaba de forma automatizada, a alta velocidad y de forma algorítmica las órdenes para ejecutar en el mercado. Dentro del código tenía la funcionalidad «Power Peg», que ya no usaba desde 2003. No se había borrado y estaba disponible si se la llamaba. El contador de las acciones vendidas en cada orden pasó a realizarla otra parte del código fuera de «Power Peg» desde 2005. Comenzando el 27 de julio de 2012 se inició la instalación del nuevo software SMARS por fases en los servidores durante varios días. El nuevo software contenía una etiqueta que en el antiguo activaba «Power Peg». Un técnico olvidó realizar una copia del nuevo código RLP a uno de los ocho servidores SMARS que gestionaban las órdenes de compra y venta de acciones automatizadas. El 1 de agosto de 2012 el servidor no actualizado al ejecutar el antiguo código «Power Peg» mandó millones de órdenes porque el contador de acciones ejecutadas en cada orden no se comunicaba a SMARS y entonces el proceso de compra no se paraba nunca. En un intento de solucionar el problema desinstalaron el nuevo código RLP de los siete servidores que funcionaban correctamente, lo que agravó el problema. En 45 minutos ejecutó 4 millones de operaciones en 154 valores moviendo 397 millones de acciones, cuando en su lugar debería haber ejecutado 212 órdenes de pequeña entidad. Knight Capital perdió 460 millones de USD y la SEC le impuso una multa de 12 millones de USD por violar regulaciones de bolsa.

### Boeing 737 MAX

Dos accidentes del avión Boeing 737 MAX en 2018 y 2019 llevaron a que el 13 de marzo de 2019 la FAA iniciara la Suspensión de vuelo del Boeing 737 MAX durante meses por fallos en el software MCAS (Sistema de Aumento de Características de Maniobra, en inglés, Manoeuvring Characteristics Augmentation System). Fallecieron 346 personas en los accidentes. La FAA permitía a fabricantes como Boeing emitir certificados de vuelo para sus aviones. En noviembre de 2019 la FAA suspendió la capacidad de Boeing para emitir certificados para los aviones MAX.

El MCAS en el MAX se diseñó para activarse usando la señal de uno de los dos sensores de ángulo de ataque del avión, haciéndolo susceptible al punto único de fallo (Single point of failure). Cuando MCAS detecta que el avión está en modo manual con los flaps arriba y con un ángulo de ataque elevado, ajusta el estabilizador horizontal para bajar el morro y que el piloto no suba demasiado rápido y produzca una caída en pérdida. Aunque el sistema MCAS podía causar picados no intencionados, no se mencionaba en los manuales de vuelo y entrenamiento, por lo que los pilotos lo desconocían. En marzo de 2019 quedaron en tierra 387 aviones MAX que realizaban 8600 vuelos semanales para 59 compañías aéreas. En enero de 2020 Boeing calculó que en 2019 perdió 18 400 millones de USD y le cancelaron 183 pedidos de MAX. En 2019 el precio de un Boeing 737 MAX iba de 100 a 135 millones de USD.

### Therac-25

La Therac-25 fue una máquina de radioterapia producida por AECL, sucesora de los modelos Therac-6 y Therac-20 (las unidades anteriores fueron producidas en asociación con CGR). El aparato estuvo comprometido en al menos seis accidentes entre 1985 y 1987, en los que varios pacientes recibieron sobredosis de radiación. Tres de los pacientes murieron como consecuencia directa. Estos accidentes pusieron en duda la fiabilidad del control por software de sistemas de seguridad crítica, convirtiéndose en caso de estudio en la informática médica y en la ingeniería de software. La comisión investigadora concluyó que las causas primarias de los accidentes fueron malas prácticas de desarrollo, análisis de requerimientos y un mal diseño de software, y no por errores aislados en el código fuente. En particular, el programa de la Therac-25 fue diseñado de tal manera que era casi imposible encontrar y subsanar fallos automáticamente.

El sistema no usaba un sistema operativo estándar. En su lugar operaba con un sistema operativo propio escrito en lenguaje ensamblador PDP-11 para funcionar en el ordenador 32K PDP-11/23. Cuando el sistema notificaba un error y detenía los rayos X, solamente mostraba el mensaje «MALFUNCTION» (error de funcionamiento) seguido de un número del 1 al 64. El manual de la máquina no explicaba el problema ni mostraba los códigos de error, y por lo tanto el operario acababa por cerrar la advertencia y proceder con el tratamiento. El personal de AECL y los operadores de las máquinas inicialmente no creyeron en las quejas de los pacientes por la alta confianza que tenían en la máquina.

La ingeniería había reutilizado código de modelos más antiguos (Therac-6 y Therac-20), que sí que contaban con sistemas de seguridad mecánicos.

El fallo solo ocurría cuando se introducía rápidamente una secuencia particular de teclas en la terminal VT100, que controlaba la computadora PDP-11 de la Therac-25. El operador había rellenado todas las casillas y estaba en la casilla de órdenes cuando se daba cuenta que había un error en la casilla del tipo de haz que contenía una X (Rayos X) cuando debía contener una E (haz de Electrones). Para corregirlo usaba el cursor ↑ hasta subir a la casilla, escribir una E y bajar con el cursor ↓ hasta la casilla de órdenes, escribir una B y pulsar ↵ Entrar. La secuencia completa era ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ E ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ B ↵ Entrar. Si esta secuencia se realizaba en menos de 8 segundos la máquina producía una radiación que podía llegar a ser hasta 1000 veces la que se pretendía aplicar.

Esto ocurría muy raramente y se desconocía que existiera tal error de condición de carrera (race condition) en el que la salida o estado de un proceso es dependiente de una secuencia de eventos que se ejecutan en orden arbitrario y van a trabajar sobre un mismo recurso compartido. Se puede producir un error cuando dichos eventos no llegan (se ejecutan) en el orden que el programador esperaba.

El programa cambiaba la variable bandera «Class3» incrementándola cada vez que ejecutaba la rutina de prueba de ajuste, en vez de asignarle un valor fijo. La variable «Class3» tenía 1 byte de longitud y sus valores posibles iban de 0 a 255. Cuando el valor era 255 y se sumaba 1, la variable «Class3» pasaba a valer 0. Cuando la variable «Class3» valía 0 indicaba que se podía lanzar el haz de electrones y no se comprobaba la posición del colimador.

La rutina de prueba de ajuste se ejecutaba cientos de veces en cada sesión para un paciente. Una vez de cada 256 ejecuciones de la rutina, la variable «Class3» tenía el valor 0 (no intencionado), el colimador no se comprobaba y cualquier fallo en el colimador no se detectaba. La sobredosis se producía si el operador apretaba el botón Set en el preciso momento en que la variable «Class3» pasaba de 255 a 0 (desbordamiento). Entonces el software aplicaba la máxima potencia de 25 MeV sin tener el objetivo en su sitio y sin escanear. AECL corrigió este problema asignando a la variable «Class3» un valor distinto de 0 cada vez que pasaba por la rutina de prueba de ajuste, en lugar de incrementarla.

### OpenSSL

Un usuario del paquete Debian OpenSSL notificó un aviso para su rectificación. En el proceso de arreglo de la incidencia un programador estropeó el generador de números aleatorios. El parche defectuoso se lanzó en septiembre de 2006 con la versión OpenSSL 0.9.8c-1. Hasta abril de 2008 no se descubrió el problema. Todas las claves criptográficas generadas con esa versión están comprometidas porque los números «aleatorios» son fácilmente predecibles, y los datos encriptados con ellas también son vulnerables. Esto supuso una amenaza en muchas aplicaciones que se apoyan en la encriptación como S/MIME, Tor, conexiones protegidas por SSL o TLS y SSH. Se corrigió en la versión OpenSSL 0.9.8c-4etch3.

Heartbleed (español: hemorragia de corazón) es un agujero de seguridad de software en la biblioteca de código abierto OpenSSL, solo vulnerable en su versión 1.0.1f, que permite a un atacante leer la memoria de un servidor o un cliente, permitiéndole por ejemplo, conseguir las claves privadas SSL de un servidor.

El código vulnerable fue adoptado y usado ampliamente con el lanzamiento de la versión 1.0.1 de OpenSSL el 14 de marzo de 2012. El soporte de Heartbeat estaba habilitado de forma predeterminada, causando que las versiones afectadas fueran vulnerables por defecto.

La «RFC 6520 Heartbeat Extension» prueba los enlaces de comunicación segura TLS/DTLS al permitir que un ordenador en un extremo de una conexión envíe un mensaje de "solicitud de latido de corazón" ("Heartbeat Request"), que consiste en una carga útil, típicamente una cadena de texto, junto con la longitud de dicha carga útil como un entero de 16-bits. El equipo receptor debe entonces enviar la misma carga exacta de vuelta al remitente. Las versiones afectadas de OpenSSL asignan un búfer de memoria para el mensaje a devolver basado en el campo de longitud en el mensaje de solicitud, sin tener en cuenta el tamaño real de la carga útil de ese mensaje. Debido a esta falla de revisión de los límites apropiados, el mensaje devuelto consta de la carga útil, posiblemente seguido de cualquier otra cosa que sea que esté asignada en el buffer de memoria. La Agencia Tributaria de Canadá reportó el robo de números de la Seguridad Social que pertenecen a 900 contribuyentes, y declaró que fueron accedidos a través de la explotación del fallo durante un período de seis horas el 8 de abril de 2014. Cuando el ataque se descubrió, la agencia cerró su sitio web y amplió el plazo de presentación de los contribuyentes del 30 de abril al 5 de mayo. La primera versión corregida, 1.0.1g, fue lanzada el día 7 de abril de 2014.

## En la cultura popular

* En la película "Brazil" (1985), un error en un apellido debido a una mosca caída en la cabecera de un teletipo provoca la detención errónea de un ciudadano inocente, con consecuencias fatales para este; una suerte de dramatización basada en el caso de la polilla en el ordenador Mark II en 1947.
* La novela de Ellen Ullman The Bug (2004) trata de la búsqueda de error de software por parte de una probadora de software y un programador. El bug es apodado «The Jester» por su tendencia a aparecer en los momentos más inoportunos y amenazando el destino de la compañía.
* La película canadiense Control Alt Delete (2008) es una comedia que trata de un programador que a finales de 1999 trata de corregir errores para prevenir los problemas del error 2YK.
