No hay forma de estar absolutamente seguro de que no existen varios tipos de comportamiento indefinido (en particular, condiciones de carrera).
Sin embargo, hay una serie de herramientas que muestran un buen número de tales situaciones. Es posible que pueda probar que existe un problema actualmente con dichas herramientas, aunque no puede probar que su solución sea válida.
Algunas herramientas interesantes para este propósito:
Valgrind es un comprobador de memoria. Encuentra fugas de memoria, lecturas de memoria no inicializada, usos de punteros colgantes y accesos fuera de los límites.
Helgrind es un comprobador de seguridad de hilos. Encuentra condiciones de carrera.
Ambos trabajan por instrumentación dinámica, es decir, toman su programa como está y lo ejecutan en un entorno virtualizado. Esto los hace discretos, pero lentos.
UBSan es un verificador de comportamiento no definido. Encuentra varios casos de comportamiento indefinido de C y C ++, como desbordamientos de enteros, desplazamientos fuera de rango y cosas similares.
MSan es un comprobador de memoria. Tiene objetivos similares a los de Valgrind.
TSan es un comprobador de seguridad de hilos. Tiene objetivos similares a los de Helgrind.
Estos tres están integrados en el compilador Clang y generan código en tiempo de compilación. Esto significa que necesita integrarlos en su proceso de compilación (en particular, tiene que compilar con Clang), lo que los hace mucho más difíciles de configurar inicialmente que * grind, pero por otro lado tienen una sobrecarga de tiempo de ejecución mucho menor.
Todas las herramientas que enumeré funcionan en Linux y algunas de ellas en MacOS. Todavía no creo que ningún trabajo en Windows sea confiable.