2010-06-10 10 views
11

¿Hay alguna manera de saber si el programa tiene un comportamiento indefinido en C++ (o incluso C), salvo la memorización de toda la especificación?Cómo detectar el comportamiento indefinido

La razón por la que pregunto es que he notado una gran cantidad de casos de programas working in debug but not release debido a un comportamiento indefinido. Sería bueno si hubiera una herramienta que al menos ayudara a detectar UB, entonces sabemos que existe la posibilidad de problemas.

Respuesta

-3

Un buen compilador, como el compilador Intel C++, debería poder detectar el 99% de los casos de comportamiento indefinido. Tendrá que investigar las banderas y los interruptores para usar. Como siempre, lea el manual.

+1

99%? Falsa sensación de seguridad. Un buen compilador puede atrapar más problemas que uno malo, pero todavía es solo una fracción de todos los casos posibles. – jalf

2

Bueno, this artículo cubre la mayoría de los aspectos ..

1

No estoy al tanto de cualquier herramienta de software para detectar todas las formas de UB. Obviamente, usar las advertencias de su compilador y posiblemente la pelusa u otro verificador de código estático puede ayudar mucho.

Otra cosa que ayuda mucho es simplemente la experiencia: cuanto más programes el lenguaje, más verás constructos que parecen sospechosos y podrás atraparlos antes en el proceso.

2

Creo que puede usar una herramienta de coverity para detectar errores que conducen a un comportamiento indefinido.

Supongo que podría usar theorem provers (solo conozco Coq) para asegurarse de que su programa hace lo que quiere.

+0

+1, no había visto el producto de cobertura antes. ¿Alguna idea de cómo se compara con PC-Lint? –

+0

coverity es muy conocida en el mundo académico ... Lanzan cada año un informe de errores encontrados en software gratuitos .. No tengo mucha experiencia con PC-Lint o Coverity (parece que Coverity dice ser mejor , pero PC-Lint hace lo mismo, en la portada). Lo único que sé es que las grandes corporaciones requieren piezas de software para ser certificadas por la cobertura – LB40

3

herramientas de análisis de código estático como PC-Lint pueden ayudar mucho aquí

+0

+1: para necesidades realmente específicas, también puede usar Coccinelle. (amo esta herramienta). Puede parchear, pero también detectar patrones – LB40

+0

@LB gracias, no había oído hablar de Coccinelle, debe buscarlo. Siempre atentos a las nuevas herramientas –

+0

para coccinelle, http://coccinelle.lip6.fr/ ... también hay férulas ... – LB40

15

estándares de buena codificación. Protegerte de ti mismo Aquí están algunas ideas:

  1. El código debe compilar en el nivel más alto de advertencia ... sin advertencias. (En otras palabras, su código no debe activar advertencias en absoluto cuando se establece en el nivel más alto.) Active el indicador de advertencia de error en todos los proyectos.

    Esto significa un trabajo extra cuando usa bibliotecas de otras personas ya que es posible que no lo hayan hecho. También encontrará que hay algunas advertencias que son inútiles ... desactívelas individualmente, como lo decida su equipo.

  2. Siempre use RAII.

  3. ¡Nunca use moldes de estilo C! ¡Nunca! - Creo que hay un par de casos raros en los que tienes que romper esto, pero probablemente nunca los encuentres.

  4. Si debe reinterpret_cast o enviar a void, utilice una envoltura para asegurarse de que siempre está realizando el fundido en/del mismo tipo. En otras palabras, envuelva su puntero/objeto en un boost::any y coloque un puntero en lo que necesite y en el otro lado haga lo mismo. ¿Por qué? Porque siempre sabrá de qué tipo de reinterpret_cast y el boost::any hará cumplir que ha emitido el tipo correcto después de eso. Es lo más seguro que puedes obtener.

  5. Siempreinicializar las variables en el punto de la declaración (o en inicializadores del constructor cuando en una clase).

Hay más, pero esas son algunas de las más importantes para empezar.

Nadie puede memorizar el estándar. Lo que hacemos los programadores de C++ intermedios a avanzados es utilizar construcciones que sabemos que son seguras y protegernos de nuestra naturaleza humana ... y no usamos construcciones que no son seguras a menos que tengamos que hacerlo y luego tenemos un cuidado especial para asegurarnos de que el peligro está envuelto en una agradable interfaz segura que se prueba al infierno y viceversa.

Una cosa importante recordar que es universal en todos los idiomas es:

hacer sus construcciones fácil de usar correctamente y difícil de usar de forma incorrecta

+0

+1 consejo de sonido – fredoverflow

+0

+2 - consejos muy buenos. – obelix

+0

+ 3- Diría más que sonido ... consejos de supervivencia? pero, ¿qué ocurre si tienes un comportamiento identificado? – LB40

2

clang se esfuerza para producir advertencias cuando indefinido comportamiento se encuentra.

+1

+1 para ** Clang **. –

5

No es posible detectar un comportamiento indefinido en todos los casos. Por ejemplo, considere x = x++ + 1;. Si estás familiarizado con el idioma, sabes que es UB. Ahora, *p = (*p)++ + 1; es obviamente también UB, pero ¿qué pasa con *q = (*p)++ + 1;? Eso es UB si q == p, pero aparte de eso está definido (si se ve incómodo). En un programa dado, podría ser posible probar que p y q nunca serán iguales al llegar a esa línea, pero eso no se puede hacer en general.

Para ayudar a detectar UB, use todas las herramientas que tenga. Los buenos compiladores advertirán al menos los casos más obvios, aunque es posible que deba utilizar algunas opciones de compilación para obtener la mejor cobertura. Si tiene más herramientas de análisis estático, úselos.

Las revisiones de código también son muy buenas para detectar estos problemas. Úselos, si tiene más de un desarrollador disponible.

0

Simple: No haga cosas que no sabe que puede hacer.

  • Cuando se está seguro o tiene la sensación de pescado, comprobar la referencia
+0

Esto solo funciona si ya sabes que no sabes lo que puedes hacer. Muchas personas [se les enseñaron las cosas incorrectas] (http://stackoverflow.com/questions/2979209/using-fflushstdin) o no conocen literalmente [miles] (https://connect.microsoft.com/VisualStudio/feedback/details/547423) [of] (https://connect.microsoft.com/VisualStudio/feedback/details/519445) [edge] (http://stackoverflow.com/questions/1831316) [cases] (http://stackoverflow.com/questions/367633/367662#367662) - simplemente no hay manera de * verificar la referencia * por cada fragmento de código no trivial que se escriba ... –

+0

@BlueRaja: si a las personas se les enseñan las cosas incorrectas, escribirán programas malos sin importar qué. Si las personas están dispuestas a llegar al límite sin mirar, se encontrarán con casos extremos, pase lo que pase. En cualquiera de esos casos, realmente no importa si se trata de un comportamiento indefinido o un comportamiento que está definido pero no necesariamente lo que esperaba. No es tan difícil aprender a programar en C o C++ de forma segura, y si eres inteligente, verificas cuándo dejas tu zona de confort en cualquier idioma. –

0

Desafortunadamente, no hay manera de manera de detectar todos UB. Tendría que resolver el problema de detención para hacer eso.

Lo mejor que puede hacer es saber que muchas de las reglas como sea posible, mirar hacia arriba cuando está en duda, y consultar con otros programadores (a través de la programación en parejas, las revisiones de código o pregunta sólo SO)

La compilación con tantas advertencias como sea posible y bajo múltiples compiladores puede ayudar. Y ejecutar el código a través de herramientas de análisis estáticas como Valgrind puede detectar muchos problemas.

Pero, en última instancia, ninguna herramienta puede detectarlo todo.

Un problema adicional es que muchos programas realmente tienen que confiar en UB. Algunas API lo requieren, y solo asumen que "funciona en todos los compiladores".OpenGL lo hace en uno o dos casos. La API Win32 ni siquiera se compilará bajo un compilador compatible con los estándares.

Por lo tanto, incluso si tuviera una herramienta mágica de detección de UB, aún así se dispararía por los casos que no están bajo su control.

+0

Me doy cuenta de eso, pero también tendría que resolver el problema de detención para detectar todos los desbordamientos de búfer, esto no ha impedido que las personas desarrollen programas que hacen un buen trabajo. Sin embargo, un poco interesante sobre Win32 API que requiere UB no lo sabía. –

+0

El caso es que resolví el problema de detención. –

+1

Una implementación no debería resolver el problema de detención para encontrar todo el Comportamiento indefinido; simplemente tendría que definir qué ocurre en cada caso que el estándar C deja indefinido. Un compilador podría producir un archivo de salida con una implementación de máquina virtual y una imagen de memoria para él, y documentar el comportamiento de la máquina virtual en todos los casos; el código producido por tal compilador no tendría * ningún * comportamiento indefinido. – supercat

Cuestiones relacionadas