vscode visual studio para configurar compile compilar code aserciones c++ debugging reference

visual - C++ capturando referencia colgante



compile c++ visual studio code windows (7)

Supongamos que el siguiente fragmento de código

struct S { S(int & value): value_(value) {} int & value_; }; S function() { int value = 0; return S(value); // implicitly returning reference to local value }

el compilador no produce advertencia (-Wall), este error puede ser difícil de detectar.

¿Qué herramientas hay para ayudar a detectar estos problemas?


No creo que ninguna herramienta estática pueda captar eso, pero si usa Valgrind junto con algunas pruebas de unidad o cualquier código que se cuelgue (falla seg), puede encontrar fácilmente dónde se hace referencia a la memoria y dónde se asignó originalmente.


Tu código ni siquiera debería compilarse. Los compiladores que conozco no compilarán el código o, por lo menos, lanzarán una advertencia.

Si en lugar de eso quiere decir return S(value) , entonces, por el bien del cielo COPIE PEGUE EL CÓDIGO QUE PUBLICA AQUÍ .

Reescribir e introducir errores tipográficos solo significa que es imposible para nosotros adivinar realmente los errores sobre los que está preguntando , y cuáles fueron los accidentes que debemos ignorar.

Cuando publique una pregunta en cualquier lugar de Internet, si esa pregunta incluye código, PUBLICAR EL CÓDIGO EXACTO .

Ahora, asumiendo que esto fue en realidad un error tipográfico, el código es perfectamente legal, y no hay ninguna razón para que una herramienta lo advierta.

Mientras no intente desreferenciar la referencia colgante, el código es perfectamente seguro.

Es posible que algunas herramientas de análisis estático (Valgrind o MSVC con / analice, por ejemplo) puedan advertirle sobre esto, pero no parece tener mucho sentido porque no está haciendo nada incorrecto. Estás devolviendo un objeto que contiene una referencia colgante. No está devolviendo directamente una referencia a un objeto local (que los compiladores generalmente advierten), sino un objeto de nivel superior con un comportamiento que podría hacer que sea perfectamente seguro de usar, incluso si contiene una referencia a un objeto local que se ha apagado. de alcance


Creo que no es posible detectar todo esto, aunque algunos compiladores pueden dar advertencias en algunos casos.

También es bueno recordar que las referencias son realmente punteros bajo el capó, y muchos de los escenarios de lanzamiento de disparos posibles con punteros todavía son posibles.

Para aclarar a qué me refiero con "punteros bajo el capó", tome las siguientes dos clases. Uno usa referencias, los otros indicadores.

class Ref { int &ref; public: Ref(int &r) : ref(r) {}; int get() { return ref; }; }; class Ptr { int *ptr; public: Ptr(int *p) : ptr(p) {}; int get() { return *ptr; }; };

Ahora, compare en el código generado para los dos.

@@Ref@$bctr$qri proc near // Ref::Ref(int &ref) push ebp mov ebp,esp mov eax,dword ptr [ebp+8] mov edx,dword ptr [ebp+12] mov dword ptr [eax],edx pop ebp ret @@Ptr@$bctr$qpi proc near // Ptr::Ptr(int *ptr) push ebp mov ebp,esp mov eax,dword ptr [ebp+8] mov edx,dword ptr [ebp+12] mov dword ptr [eax],edx pop ebp ret @@Ref@get$qv proc near // int Ref:get() push ebp mov ebp,esp mov eax,dword ptr [ebp+8] mov eax,dword ptr [eax] mov eax,dword ptr [eax] pop ebp ret @@Ptr@get$qv proc near // int Ptr::get() push ebp mov ebp,esp mov eax,dword ptr [ebp+8] mov eax,dword ptr [eax] mov eax,dword ptr [eax] pop ebp ret

¿Encuentra la diferencia? No hay ninguno.


Hay soluciones basadas en el tiempo de ejecución que instrumentan el código para verificar accesos inválidos al puntero. Hasta ahora, solo he utilizado mudflap (que está integrado en GCC desde la versión 4.0). mudflap intenta rastrear cada puntero (y referencia) en el código y verifica cada acceso si el puntero / referencia realmente apunta a un objeto vivo de su tipo base. Aquí hay un ejemplo:

#include <stdio.h> struct S { S(int & value): value_(value) {} int & value_; }; S function() { int value = 0; return S(value); // implicitly returning reference to local value } int main() { S x=function(); printf("%s/n",x.value_); //<-oh noes! }

Compila esto con mudflap habilitado:

g++ -fmudflap s.cc -lmudflap

y corriendo da:

$ ./a.out ******* mudflap violation 1 (check/read): time=1279282951.939061 ptr=0x7fff141aeb8c size=4 pc=0x7f53f4047391 location=`s.cc:14:24 (main)'' /opt/gcc-4.5.0/lib64/libmudflap.so.0(__mf_check+0x41) [0x7f53f4047391] ./a.out(main+0x7f) [0x400c06] /lib64/libc.so.6(__libc_start_main+0xfd) [0x7f53f358aa7d] Nearby object 1: checked region begins 332B before and ends 329B before mudflap object 0x703430: name=`argv[]'' bounds=[0x7fff141aecd8,0x7fff141aece7] size=16 area=static check=0r/0w liveness=0 alloc time=1279282951.939012 pc=0x7f53f4046791 Nearby object 2: checked region begins 348B before and ends 345B before mudflap object 0x708530: name=`environ[]'' bounds=[0x7fff141aece8,0x7fff141af03f] size=856 area=static check=0r/0w liveness=0 alloc time=1279282951.939049 pc=0x7f53f4046791 Nearby object 3: checked region begins 0B into and ends 3B into mudflap dead object 0x7089e0: name=`s.cc:8:9 (function) int value'' bounds=[0x7fff141aeb8c,0x7fff141aeb8f] size=4 area=stack check=0r/0w liveness=0 alloc time=1279282951.939053 pc=0x7f53f4046791 dealloc time=1279282951.939059 pc=0x7f53f4046346 number of nearby objects: 3 Segmentation fault

Un par de puntos a considerar:

  1. mudflap puede ajustarse en lo que debe verificar y hacer exactamente. lea http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging para más detalles.
  2. El comportamiento predeterminado es generar un SIGSEGV en una violación, esto significa que puede encontrar la violación en su depurador.
  3. mudflap puede ser una perra, en particular cuando estás interactuando con bibliotecas que no están compiladas con soporte mudflap.
  4. No ladrará en el lugar donde se crea la referencia colgante (return S (value)), solo cuando se desreferencia la referencia. Si lo necesita, necesitará una herramienta de análisis estático.

PD: una cosa a tener en cuenta fue agregar una verificación NO PORTÁTIL al constructor de copia de S (), que afirma que value_ no está vinculado a un entero con una vida útil más corta (por ejemplo, si * está ubicado en un " más antigua "ranura de la pila que el número entero está obligado a). Esto es altamente específico para la máquina y posiblemente sea complicado hacerlo bien, por supuesto, pero debería estar bien, siempre y cuando solo sea para la depuración.


Hay una guía que sigo después de haber sido vencido por esta cosa exacta:

Cuando una clase tiene un miembro de referencia (o un puntero a algo que puede tener una vida que usted no controla), haga que el objeto no se pueda copiar.

De esta forma, reduces las posibilidades de escapar del alcance con una referencia que cuelga.


Debe usar una tecnología basada en instrumentación en tiempo de compilación. Si bien valgrind podía verificar todas las llamadas a funciones en tiempo de ejecución (malloc, gratis), no podía verificar solo el código .

Según su arquitectura, IBM PurifyPlus encuentra algunos de estos problemas. Por lo tanto, debe encontrar una licencia válida (o usar una de su compañía) para usarla o probarla con la versión de prueba.


Este es un código perfectamente válido.

Si llama a su función y vincula el temporal a una referencia constante, el alcance se prolonga.

const S& s1 = function(); // valid S& s2 = function(); // invalid

Esto está explícitamente permitido en el estándar C ++ .

Ver 12.2.4:

Hay dos contextos en los que los temporales se destruyen en un punto diferente al final de la expresión completa.

y 12.2.5:

El segundo contexto es cuando una referencia está vinculada a un temporal. El temporal al que está vinculada la referencia o el temporal que es el objeto completo de un subobjeto al que está vinculada la referencia persiste durante la vigencia de la referencia, excepto: [...]