No hay forma de estar absolutamente seguros de que no existan varios tipos de comportamiento indefinido (en particular las condiciones de carrera).
Sin embargo, hay una serie de herramientas que muestran una buena cantidad de tales situaciones. Es posible que pueda probar que existe un problema actualmente con tales herramientas, aunque no puede probar que su solución es válida.
Algunas herramientas interesantes para este propósito:
Valgrind es un verificador de memoria. Encuentra pérdidas de memoria, lecturas de memoria no inicializada, usos de punteros colgantes y accesos fuera de límites.
Helgrind es un verificador de seguridad de hilos. Encuentra condiciones de carrera.
Ambos funcionan mediante instrumentación dinámica, es decir, toman su programa tal cual y lo ejecutan en un entorno virtualizado. Esto los hace no intrusivos, pero lentos.
UBSan es un verificador de comportamiento indefinido. Encuentra varios casos de comportamiento indefinido de C y C ++, como desbordamientos de enteros, cambios fuera de rango y cosas similares.
MSan es un verificador de memoria. Tiene objetivos similares a los de Valgrind.
TSan es un verificador de seguridad de hilos. Tiene objetivos similares a Helgrind.
Estos tres están integrados en el compilador de Clang y generan código en tiempo de compilación. Esto significa que debe integrarlos en su proceso de compilación (en particular, debe 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. No creo que ningún trabajo en Windows sea confiable todavía.