c++ - seccion - race condition vulnerability
Formas de encontrar una condiciĆ³n de carrera (9)
Tengo un poco de código con una condición de carrera ... Sé que es una condición de carrera porque no ocurre de manera consistente, y parece ocurrir más a menudo en máquinas de doble núcleo.
Nunca sucede cuando estoy rastreando. Aunque existe la posibilidad de que también sea un punto muerto. Al analizar las etapas de finalización de los registros donde esto ocurre y no ocurre, he podido localizar este error en una sola función. Sin embargo, no sé en qué parte de la función esto está sucediendo. No está en el nivel superior.
Agregar instrucciones de registro o puntos de interrupción va a cambiar el tiempo si es una condición de carrera, y evitar que esto suceda.
¿Hay alguna técnica que pueda usar aparte de obtener un analizador de condiciones de carrera que me permita identificar dónde está sucediendo esto?
Esto está en Visual Studio 9, con C ++ (de la variedad no administrada).
De hecho, hay algunos intentos de encontrar condiciones de carrera de forma automática.
- Comprobador de carrera basado en cerrojo
- Sucede antes de la detección de la carrera
- Detección de carrera híbrida
Otro término que leí junto con la detección de la condición de carrera es RaceFuzzer, pero no pude encontrar información realmente útil al respecto.
Creo que este es un campo de investigación relativamente joven, por lo que hay, por lo que sé, principalmente artículos teóricos sobre este tema. Sin embargo, intente buscar en Google una de las palabras clave anteriores, tal vez encontrará algo de información útil.
La mejor forma que conozco para realizar un seguimiento de estos es utilizar CHESS en Visual Studio. Esta no es una herramienta simple de usar, y probablemente requerirá probar subsecciones de su aplicación progresivamente. Buena suerte.
Podría intentar publicar el código. Intel también ofrece varias herramientas paralelas que puedes probar.
Pon duerme en varias partes de tu código. Algo que es seguro para la realización de hilos será seguro incluso si (o el código asíncrono) duerme por unos segundos.
Por lo tanto, el método de sledgehammer para mí ha sido el siguiente, que requiere mucha paciencia y, en el mejor de los casos, puede llevarlo por el camino correcto. Usé esto para descubrir qué estaba pasando con este problema en particular. He estado usando puntos de rastreo, uno al comienzo de la función sospechosa de alto nivel y uno al final. Mueve el punto de seguimiento hacia abajo. Si agregar el punto de rastreo al principio de la función hace que su error deje de suceder, mueva el punto de rastreo hacia abajo hasta que pueda reproducir la condición nuevamente. La idea es que el punto de seguimiento no afectará el tiempo si lo coloca después de la llamada que finalmente desencadena un código inseguro, pero lo hará si lo coloca antes. Además, tenga en cuenta su ventana de salida. ¿Entre qué mensajes está ocurriendo tu error? Puede usar puntos de referencia para restringir este rango también.
Una vez que reduzca su error a una región manejable de código, puede agregar puntos de corte y observar qué están haciendo los otros hilos en este momento.
También puede ser un recurso que no está protegido, lo que puede explicar el comportamiento no consistente (especialmente si en un solo núcleo funciona bien y no en doble núcleo). En cualquier caso, la revisión del código (tanto para las condiciones de carrera como para el código fuente no seguro para subprocesos) puede ser el camino más corto hacia la solución.
Tuve algo de suerte al usar los puntos de seguimiento de Visual Studio para encontrar las condiciones de carrera. Por supuesto, todavía afecta el tiempo, pero en los casos que lo usé, al menos, no fue suficiente para evitar por completo las condiciones de carrera. Parecía menos perjudicial que el registro dedicado, al menos.
Aparte de eso, intente publicar el código permitiendo que otros lo revisen. Solo estudiar el código en detalle no es una mala forma de encontrar las condiciones de carrera.
Puede usar herramientas como Intel Inspector que pueden verificar ciertos tipos de condiciones de carrera.
Hay una herramienta incluida en CLang y gcc 4.8+ llamada ThreadSanitizer .
Usted compila su código usando el -fsanitize=thread
Ejemplo:
$ cat simple_race.cc
#include <pthread.h>
#include <stdio.h>
int Global;
void *Thread1(void *x) {
Global++;
return NULL;
}
void *Thread2(void *x) {
Global--;
return NULL;
}
int main() {
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, NULL);
pthread_create(&t[1], NULL, Thread2, NULL);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
}
Y la salida
$ clang++ simple_race.cc -fsanitize=thread -fPIE -pie -g
$ ./a.out
==================
WARNING: ThreadSanitizer: data race (pid=26327)
Write of size 4 at 0x7f89554701d0 by thread T1:
#0 Thread1(void*) simple_race.cc:8 (exe+0x000000006e66)
Previous write of size 4 at 0x7f89554701d0 by thread T2:
#0 Thread2(void*) simple_race.cc:13 (exe+0x000000006ed6)
Thread T1 (tid=26328, running) created at:
#0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
#1 main simple_race.cc:19 (exe+0x000000006f39)
Thread T2 (tid=26329, running) created at:
#0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
#1 main simple_race.cc:20 (exe+0x000000006f63)
==================
ThreadSanitizer: reported 1 warnings