Copy Link
Add to Bookmark
Report
SET 036 0x0E
-[ 0x0E ]--------------------------------------------------------------------
-[ Heisenbugs & Company ]----------------------------------------------------
-[ by blackngel ]----------------------------------------------------SET-36--
^^
*`* @@ *`* HACK THE WORLD
* *--* *
## by blackngel <blackngel1@gmail.com>
||
* *
* * (C) Copyleft 2009 everybody
_* *_
1 - Prologo
2 - Introduccion
3 - Heisenbugs
3.1 - Assert()
3.2 - Aleatoriedad
3.3 - Memoria no inicializada
3.4 - El escondite
3.5 - Psicologia
4 - Otros bugs
5 - Curiosidad
6 - Conclusion
7 - Referencias
---[ 1 - Prologo
Que locura te traigo hoy?
Pues algo que se ha visto ya desde hace un tiempo en la red. Ciertas clases
de bugs que pueden resultar ser de lo mas esotericos y, lo que es peor, la
mayoria de las veces complicados de encontrar y/o solucionar.
Esto no es ninguna investigacion, como ya he dicho, sino un recopilatorio
de informacion que he encontrado a lo largo de la red, un poco de expereincia
propia y la ayuda de algun que otro libro (lease Referencias).
Si creias haberlo visto todo, si pensabas que jamas ya nada te iva a
soprender... entonces preparate para lo que viene a continuacion...
---[ 2 - Introduccion
Organizacion? Muy sencillo:
1 - Explicaremos que son los 'heisenbugs', donde aparecen, en que
condiciones se producen y que puedes hacer tu para encontrarlos
y solucionarlos.
2 - Definiremos en que consisten otro tipo bugs mencionados en la red
sin entrar en otro tipo de detalles.
Lo demas es dar rienda suelta a tu imaginacion...
---[ 3 - Heisenbugs
En realidad esto es basicamente una traduccion de la documentacion encontrada
en estos dos lugares:
(1) Debugging Heisenbugs [1]
(2) Programacion en Linux: Casos Practicos - Capitulo 12 [2]
- Y Otras elucubraciones de experiencia personal.
Pero blackngel, que es un 'heisenbug'? Ahora mismo, no te impacientes:
Como definicion principal diriamos que es un bug que desaparece (manda huevos)
o modifica su comportamiento cuando intentas depurarlo (o debuggearlo).
Pero tambien podriamos calificar con este nombre a la mayoria de los bugs
producidos por condiciones de carrera (aquel en el que el acceso simultaneo
a un recurso del sistema puede provocar un error de proceso).
El nombre hace referencia al principio de incertidumbre de Heisenberg que
describe, segun la fisica cuantica, la imposibilidad de conocer en un mismo
instante de tiempo la posicion y velocidad de una particula. Cuanto mas se
conoce una de las variables, mas inconcreta se vuelve la otra.
El problema principal radica en el llamado "efecto del observador" que viene
a decir que el hecho de observar la particula, la modifica. O lo mismo, no
podemos observar la particula sin alterarla.
Y como ya habreis supuesto, de ahi la analogia, cuando queremos depurar el
bug, alteramos el codigo y este ya no esta (el muy espabilado).
---[ 3.1 - Assert()
Para empezar explicaremos uno de los ejemplos mas sencillos de entender,
dado que lo que venga a posteriori podria parecer algo perteneciente a un
mundo paralelo.
Que es una asercion?
Pues podriamos decir que es una declaracion o afirmacion que usted hace
y que deberia ser verdadera en el momento en que se compruebe.
Por ejemplo, podrias utilizar una variable para controlar tu programa
como si de un booleano se tratase y comprobar que este sigue siendo
verdadero en distintas partes del codigo.
int ctr = 1; /* Variable Global como Booleana */
...
... /* Codigo que podria modificar 'ctr' o no */
...
int funcion01(char *arg1, char *arg2) {
assert(ctr == 1);
printf("%s %s\n", arg1, arg2);
...
...
...
}
Puede parecerte que consigues lo mismo con un condicional, pero hay dos
grandes diferencias:
1.- 'assert()' se utiliza normalmente para comprobar que un programa
funciona correctamente durante el proceso de desarrollo y las
llamadas son eliminadas en el proceso de produccion.
2.- Cuando la condicion no se cumple, 'assert()' llama (por telefono)
a su vez a 'abort()' e imprime un mensaje con informacion variada
acerca del error ocurrido.
Hay mas detalles y diferencias, pero eso ahora no nos interesa.
Lo mas importante es que para eliminar estas llamadas usted no tiene
mas que utilizar la opcion '-DNDEBUG' a la hora de compilar su programa.
Realmente estas llamadas a 'assert()' no son extirpadas como si
sufrieran algun tipo de cirujia. Lo que ocurre en realidad es que la
condicion que se le pasa como argumento desaparece y la funcion deja
continuar el programa como si todo fuera normal.
El ejemplo anterior (vulgar como el solo) no tiene ninguna clase de
problema. Los 'heisenbugs' llegan cuando utilizamos condiciones que
implican efectos colaterales.
- Explicate!
- Ya voy mama...
Si utilizas algo como:
assert(*k++ != '\t');
Mientras estamos en la etapa de desarrollo, todo funcionara a la
perfeccion, pues seguramente la condicion se cumpla tal y como
esperamos; pero cuando compilas la aplicacion con '-DNDEBUG' para
la etapa de produccion ocurre que:
1.- La condicion de la asercion desaparece (BIEN).
2.- El incremento del puntero 'k' nunca se produce
y esto podria causarte mil y un errores a partir
de ese punto cuando lo utilices (MAL, MAL Y MAL)
La conclusion es que el programa probablemente fallara cuando tus
estimados clientes lo utilicen. Y cuando te avisen del fallo y tu
vuelvas a intentar depurarlo con las aserciones activas, este
desaparecera y todo parecera funcionar perfectamente de nuevo.
Asi una y otra vez hasta que caigas en la cuenta o hayas leido
este articulo.
---[ 3.2 - Aleatoriedad
Los motivos o causas por los que se puede producir un 'heisenbug' son
tan variopintas como las de un bug normal, pero ciertos factores influyen
mas a la hora de que estos aparezcan.
Los factores de azar son una de las causas mas probables. En particular
la generacion de numeros aleatorios.
Muchas veces el error comienza cuando uno piensa que estos numeros son
realmente aleatorios, cuando su pseudo-aleatoriedad puede quedar la
mayoria de las veces en entredicho.
Otros factores posibles pueden ser:
- El orden de procesamiento de datos en aplicaciones multi-hilo.
- Dar por asumido el estado de un registro de la GPU (o Unidad de
Procesamiento Grafico).
- El contenido de una 'cache' que no ha sido volcada todavia a
disco ( fflush(); ).
- La entrada del usuario (malintencionada?).
- Mantener valores en una memoria incorrectamente sincronizada.
- Y mas...
La clave para solucion suele encontrarse directamente en eliminar todos
estos tipos de aleatoriedad o indeterminismo y comprobar entonces como
cambia el comportamiento de nuestra aplicacion.
---[ 3.3 - Memoria no inicializada
Con frecuencia, cuando asignamos memoria o declaramos variables, estas no son
inicializadas a ningun valor en concreto. Normalmente esto no supone ningun
problema; pero si el codigo esta diseñado pobremente o si no se entiende la
totalidad de sus implicaciones, ello podria resultar en un Heisenbug provocado
al estar usando memoria antes de que esta haya sido inicializada.
La solucion suele estar casi siempre en revertir esta situacion seteando la
memoria a valores conocidos. La otra solucion, y mas efectiva, seria que por
defecto, los compiladores nos advirtieran mediante "warnings" cuando no hagamos
un uso correcto de la memoria. Mas drastico todavia seria que la advertencia
pasara a ser un error y que el codigo no pudiera ser compilado mientras todas
las variables no hayan sido inicializadas.
A este respecto Java hizo bien su trabajo. Siempre debemos inicializar una
variable. Al momento de leer el contenido de una variable, el compilador de
Java siempre verifica que tenga un valor. De lo contrario el programa no
compilara y mostrara el error. Un ejemplo de este caso:
String saludo;
if (x < 0) {
saludo = "Hola Mundo!";
}
System.out.println(saludo);
En este caso el compilador mostrara un mensaje de error indicando que la
variable saludo no se ha inicializado con ningun valor. Como se puede observar
esta variable solo se inicia cuando se cumple una condicion, sin embargo se
indica que va a ser utilizada siempre. El compilador detecta este posible error.
Es muy sencillo de ver: La sentencia println() se ejecutara siempre, cualquiera
que sea el resultado de la condicion que le precede. Si la condicion no se
cumpliera, la variable 'saludo' nunca obtendria un valor concreto y el metodo
println() podria provocar un error.
---[ 3.4 - El escondite
Existe una gran diferencia entre eliminar definitivamente un Heisenbug, y
ocultarlo; pero esta diferencia, aunque comprensible, no es tan facil de
discernir a la hora de depurar cualquier software.
Un metodo logico para intentar elminar este bug tan resbaladizo, se basa en
sustraer parte del codigo de tu programa para comprobar si el error continua
reproduciendose. El problema radica en que creamos que el bug se encuentra
en ese pedazo de codigo si el error deja de producirse.
Podria decirse que los Heisenbugs son sensibles a los cambios de estado, y
con la eliminacion de una parte del codigo podriamos estar cambiando una de
las situaciones que provoca la ejecucion del error, y con ello lo estamos
ocultando, no resolviendo el problema en si.
Mucho mas interesante es cuando eliminamos una parte de nuestro codigo y el
bug todavia sigue reproduciendose. En esta situacion podemos estar seguros,
con una muy alta probabilidad, de que esa zona del codigo se encuentra limpia
y funciona correctamente.
Un ejemplo que se da es si estamos tratando con una aplicacion multi-hilo.
Eliminar esta capacidad y que el Heisenbug deje de reproducirse no significa
que haya sido eliminado, sino que alguna de las condiciones que propiciaban
su puesta en marcha no esta sucediendo. En cambio, si al deshacernos de esta
capacidad, el bug no desaparece, querra decir, casi con toda seguridad, que
esta funcion ha sido correctamente programada y que el error debe de estar
en algun otro escondite.
---[ 3.5 - Psicologia
Lo que aqui se viene a decir es que debemos tener una mente espcialmente
abierta para encontrar bugs de este tipo. En cualquier momento podriamos
empezar a atribuir los fallos a elmentos tales como la fuente de alimentacion,
un condensador flojo en la placa base o a la interferencia de radios o moviles
cercanos a nuestra CPU.
Cuanto antes nos deshagamos de estos desorbitados pensamientos, mas cerca
estaremos de hallar la solucion. No digo que cualquiera de estas cosas no
pudiera ocurrir, pero es remotamente improbable y la estadistica dice que
si te dedicas a estudiar tu codigo conseguiras resultados mucho antes.
Yo particularmente, en estos casos utilizaria siempre la Navaja de Occam, que
viene a decir que:
- En igualdad de condiciones la solucion mas
sencilla es probablemente la correcta.
O que:
- No ha de presumirse la existencia de mas
cosas que las absolutamente necesarias.
Tambien podriamos pensar que el bug se encuentra en el compilador y no en
nuestra aplicacion, y es verdad que estos bugs existen, pues un compilador no
deja de ser una aplicacion mas, pero su frecuencia sera nuevamente inferior y
no es el lugar adecuado para empezar a buscar.
Es realmente frustrante que cuando intentes depurar un error, este desaparezca,
y este solo y unico error puede echar por tierra todo un proyecto de gran
envergadura.
Debemos estar especialmente atentos y estar al dia con respecto a la depuracion
de esta clase de bugs escurridizos.
Podria ayudarte leer trabajos tan interesantes como los siguientes:
- Porque son diferentes los Heisenbugs de los Bohrbugs? [3]
- Encontrar y reproducir Heisenbgus en programas concurrentes [4]
---[ 4 - Otros bugs
En realidad esto es basicamente una traduccion de la documentacion encontrada
en estos dos lugares:
(1) Unusual Software Bug [5]
(2) Heisenbugs, Bohrbug, Mandelbugs, Schroedinbugs [6]
Bohrbug
=======
¿Bohr? Si, el que definio el modelo del atomo!
Se podria decir que este bug es un antagonista de los 'heisenbugs'. Al contario
que este, el 'bohrbug' no desaparece ni altera su comportamiento cuando esta
siendo buscado.
Se manifiesta siempre bajo unas condiciones bien definidas, aunque normalmente
desconocidas para el programador o usuario del software.
Suelen ser mucho mas faciles de encontrar que los 'heisenbugs' cuando estos ya
se han manifestado al menos una vez.
Mandelbug
=========
Los fractales de Mandelbrot te suenan verdad? Pues claro, esas imagenes tan
complejas pero brillantes que se crean a partir de formulas matematicas.
Por definicion se dice que un 'mandelbug' es un bug cuyas causas son tan
complejas que su comportamiento aparenta ser sumamente caotico.
Y ahora es cuando viene el lio: Unos dicen... y otros dicen mas...
Hay quien utiliza este nombre para hablar de bugs que no se comportan
caoticamente pero que se producen tras unas condiciones extremadamente
complejas y disparatadas.
Y despues, a la hora de aplicar la logica, se dice que:
1.- Todo 'heisenbug' es un 'mandelbug'.
2.- El 'mandelbug' es el antonimo complementario del 'bohrbug'.
Es de notar tambien que las causas para que este bug tan insidioso se produzca
no siempre tienen que venir de dentro. Me explico.
Otro software podria interferir de alguna forma en medio de nuestro programa,
ya sea manipulando la memoria o con cualquier otro tipo de accion inoportuna
que active la bomba.
Incluso se dice que pude producirse un largo espacio de tiempo entre la
activacion del bug y la ejecucion de sus efectos. Es decir, causa y efecto
pueden dilatarse mas de lo normal.
Schroedinbug
============
Quien no conoce al famoso "gato de Schrödinger". Ya hemos hablado de el en
el numero 32 de SET, en un articulo sobre "Inteligencia Artificial".
Resumiendo: Si metemos un gato en una caja y la cerramos, no podemos definir
si el gato esta vivo o muerto hasta que la volvamos a abrir. Por lo tanto el
gato se encuentra en un estado: vivo-muerto.
Siguiendo esta paradoja, el 'schroedinbug' solo se manifiesta cuando alguien
lee el codigo o utiliza el programa de una forma inusual o atipica.
Lo mas impresionante, es que al descubrir este bug uno se da cuenta de que
el programa jamas deberia haber funcionado correctamente y a partir de ese
momento deja de hacerlo para todo el mundo hasta que es corregido..
Lo mas normal es encontrarlos en la etapa de produccion aunque tambien son
faciles de corregir una vez hayados.
Si no te crees que puedan aparecer, desengañate. Si se te da bien el ingles
y te apetece ver un ejemplo de codigo SQL que sufrio este bug y como se
soluciono, visita esto [7].
Stotle
======
Mas dificil de inferir pero no tanto. Proviene de Aristoteles, y la idea se
basa en que todas daban por cierto lo que el decia sin cuestionar en ningun
momento sus elucubraciones. Es decir, damos por verdadero algo que podria
no serlo.
El bug 'stotle' (que no es tal bug) se basa en que el usuario introduce en
su aplicacion datos que aparentan ser correctos cuando en realidad no lo
son. Entonces este individuo se piensa que el programa es el que trabaja de
forma incorrecta siendo esto totalmente falso.
Bug en Fase Lunar
=================
Con este nombre tan bonito se define a aquellos bugs que parecen depender
de causas casi totalmente aleatorias para producirse.
Suelen encontrarse en programas que dependen de factores tales como la hora
o la fecha en que se ejectura.
Quizas el mas conocido aunque no tan aleatorio y si muy esperado sea:
- "El bug del año 2000"
Un cambio de dia, mes, año, centenario o milenio no esperado puede dar
lugar a este tipo de sucesos.
Statistical bug
===============
Se podria decir que estos bugs crecen y se hacen mas evidentes a medida
que el codigo de la aplicacion avanza.
En una pequeña porcion de codigo que maneje cifras, si esta comete un
miserable error pero este codigo vuelve a ser llamado repetidas veces en
diferentes ocasiones, el error puede convertirse en catastrofico.
Fantasma en el codigo
=====================
Son aquellos bugs que no se encuentran en la fase de pruebas o testeo y
pueden producirse al introducir un conjunto de datos unico o especial.
Su nombre viene de la idea de que el creador puede llegar a pensar que
alguien esta poseyendo su codigo dado que algo muy raro sucede sin
explicacion.
Suelen hayarse con frecuencia en partes del codigo que no son llamadas o
utilizadas habitualmente.
---[ 5 - Curiosidad
Emma McGrattan, vicepresidenta de tecnologia de la empresa Ingres y
una de las programadoras de mas alto rango en Silicon Valley, insiste
en que los hombres y las mujeres escriben codigo de forma muy diferente.
Segun su parecer, las mujeres tienen mas consideracion con aquellos
que usaran el codigo mas tarde. Suelen intercalar entre su codigo
cadenas completas de instrucciones y comentarios, para explicar por
que se escribio determinada linea y que camino utilizaron para ello.
Los hombres, por el contrario, no tienen tanta delicadeza. A menudo
?tratan de demostrar su inteligencia escribiendo un codigo muy criptico?,
segun se cuenta en el blog de Bussiness Technology de WSJ. ?Ellos tratan
de ofuscar las cosas en el codigo?, y no dejan instrucciones claras para
aquellas personas que tienen que usarlo despues.
McGrattan se jacta de que el 70-80 por ciento de las veces puede
distinguir, viendo un fragmento de codigo, si ha sido escrito por
un hombre o una mujer.
---[ 6 - Conclusion
Como siempre, espero que al menos te hayas divertido, puesto que los nombres
de estos bugs no son para menos. Esto deja claro que en este/nuestro mundo
hay gente realmente retorcida, y nosotros no vamos a ser menos.
Y ahora, si has descubierto una nueva clase de bug, si crees que nadie lo
conoce todavia y solo tu eres capaz de arreglarlo, entonces, a que estas
esperando; cuentanoslo cuanto antes y puede que te hagas famoso poniendole
tu nombre...
En cualquier caso, siempre puedes ayudar a la comunidad del software, en
especial a la del "software libre".
---[ 7 - Referencias
[1] Debugging Heisenbugs
http://cowboyprogramming.com/2008/03/23/debugging-heisenbugs/
[2] Programacion en Linux: Casos Practicos - Capitulo 12
http://www.anayamultimedia.es
[3] Heisenbugs and Bohrbugs: Why are they different?
http://www.cs.rutgers.edu/~rmartin/teaching/spring03/cs553/papers01/
06.pdf
[4] Finding and Reproducing Heisenbugs in Concurrent Programs
http://research.microsoft.com/~madanm/papers/osdi2008-CHESS.pdf
[5] Unusual Software Bug
http://en.wikipedia.org/wiki/Heisenbug#Heisenbugs
[6] Heisenbugs, Bohrbug, Mandelbugs, Schroedinbugs
http://www.seguilaflecha.com/pages/news/print.php?id=360
[7] Stupid SQL Tricks
http://blogs.msdn.com/philoj/archive/2005/10/20/483240.aspx
*EOF*