Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: kafok en 9 Noviembre 2014, 19:55 pm



Título: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 9 Noviembre 2014, 19:55 pm
Hola, mi problema es que estoy trabajando en una librería la cual estuve planificando el diseño tiempo. La libreria es una DLL que en principio esta pensada para ser linkeada de forma estatica (el diseño es mas facil y se adecua al sistema de clases que tengo). Bueno pues mi proyecto esta organizado de la siguiente manera, tengo tres proyectos los cuales es la misma libreria implementada de varias formas. El primero es un programa con su main y dentro del proyecto esta la libreria, de esta forma la testeo facilmente. Acto seguido copio el codigo en el proyecto que crea la DLL y la compilo teniendo como resultado una DLL ya testada. Por ultimo en otro proycto linkeado a la DLL hago exactamente las mismas pruebas que en el primer proyecto y asi me aseguro que la DLL funciona como debe.

Para mi este sistema es comodo ya que no tengo que andar con dos proyectos, el que compile la DLL y otro aparte para probarlo, sino que creo el codigo en uno aparte lo testeo y una vez comprobado copio y pego en el proyecto final y los resultados de los test deben ser iguales.

Aqui mi problema, resulta que en el proyecto inicial los test van de maravilla, no hay errores en la clase que estoy testando. En el proyecto que incluya la DLL no se esperan anomalias, ya que el codigo es el mismo, se comprueba que se haya contruido bien la DLL ya que el funcionamiento de las clases ya se a comprobado, pero bueno un copia y pega no esta de mas.

Ahora... llevo con este problema alrededor de un mes investigando y no hayo respuesta. Comprobando los constructores de la unica clase que llevo resulta que si se instancia de forma estatica, es decir, como variable, no da problemas (TODO ESTO EN EL PROYECTO FINAL, EN EL PRIMERO TODO FUNCIONA BIEN), pero cuando hago uso del operador new para llamar a algun constructor de una clase pasa algo rarisimo, hay veces que el programa termina correctamente, pero no crea el objeto (no se ve por pantalla) y otras que la aplicacion crashea, el tipico: Esta aplicacion a dejado de funcionar, de windows. He probado a poner el test en un bloque try, pero no me recoje ninguna excepcion, y lo mas extraño es que no pasa siempre, no siempre crashea, lo que me hace pensar que el codigo esta bien, es mas cuando no se instancia con new todo funciona bien.

¿Como puedo encontrar el error?¿como puedo saber por que Windows cierra la aplicacion asi, es decir, saber cual es la causa?

Probe a crear una libreria estatica con el mismo resultado.....  :-(

PD: no pongo el codigo pues se trata de un proyecto grande con muchisimos archivos y la clase de la que hablo contiene mucho codigo


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 9 Noviembre 2014, 20:20 pm
Usa el WinDbg; File>>Open Executable; F5 para arrancar, cuando de la excepcion usa kb ffff para ver la pila (ALT+6 para la ventana), dv parar las variables locales, .etc.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 10 Noviembre 2014, 01:29 am
Muchas, gracias, la verdad ando un poco perdido, aunque llevo unos añitos programando nunca me he visto en la necesidad de depurar, simplemente probando a cambiar cosas y observando resultados he sido capaz de solucionar problemas, rara vez me ha echo falta depurar. Bueno, al grano, no se usar WinDbg, aun hay cosas que me faltan por manejar, y sobre todo cosas de tan bajo nivel,  asi que me podrias indicar donde puedo aprender a usar este programa, o como resolver mi problema que no es mas que saber porque crashea la aplicacion


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 10 Noviembre 2014, 01:42 am
El programa tiene una extensa ayuda y sino busca en Google tutoriales; ese problema puede llegar a ser resuelto en 5 minutos (las instrucciones que te deje antes serian suficientes) o en varios dias (puede ser un problema de sincronizacion, un memory leak o vaya uno saber).


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 10 Noviembre 2014, 02:39 am
Es que cuando depuro no salta la excepcion...  :-(
Deben salir textos por pantalla pero solo salen simbolos extrañisimos cuando depuro. Hice un programa que llamara a un metodo desde un puntero nulo y si salta la excepcion pero en el mio no me salta ningun error.... No se que mas hacer, estoy desesperaisimo yaaa!!


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kub0x en 10 Noviembre 2014, 04:42 am
Estoy con Eternal, no parece gran cosa...

Ocurre una excepción no controlada, por lo que salta el filtro de excepciones por defecto del programa y por eso no llega a ejecutar tu bloque try-catch. Prueba a depurar bien, obten la stacktrace y ve paso por paso. No te rindas.

Si manejas la WinAPI podrías cambiar el filtro de excepciones no controladas por el tuyo propio usando SetUnhandledExceptionFilter pasándole tu propio callback, obteniendo una estructura del contexto del hilo donde se generó la excepción. Dicha estructura contiene la causa de la excepción, valores de los registros de propósito general y la dirección donde ocurrió la excepción. Para obtener la stacktrace usa la API StackWalk. Con esto me armé un módulo de depuración para que me facilitase el trabajo.

Saludos!

APIs a revisar:

SetUnhandledExceptionFilter -> http://msdn.microsoft.com/es-es/library/windows/desktop/ms680634%28v=vs.85%29.aspx
SymInitialize -> http://msdn.microsoft.com/en-us/library/windows/desktop/ms681351%28v=vs.85%29.aspx
StackWalk -> http://msdn.microsoft.com/en-us/library/windows/desktop/ms680650%28v=vs.85%29.aspx


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 10 Noviembre 2014, 09:52 am
Es que cuando depuro no salta la excepcion...  :-(
Deben salir textos por pantalla pero solo salen simbolos extrañisimos cuando depuro. Hice un programa que llamara a un metodo desde un puntero nulo y si salta la excepcion pero en el mio no me salta ningun error.... No se que mas hacer, estoy desesperaisimo yaaa!!

Solucion, ejecuta el WinDbg con la linea de comandos -I (loggeado como Administrador desde cmd) para configurarlo como depurador post-mortem, de esta manera se abrira automaticamente el WinDbg en cuanto se produzca la excepcion. Si solo ves simbolos extraños tenes que generar la informacion de depuracion (archivos .pdb), no se que herramientas estaras usando pero normalmente en el IDE se puede configurar facilmente.

Enabling Postmortem Debugging (http://msdn.microsoft.com/en-us/library/windows/hardware/ff542967%28v=vs.85%29.aspx)

Specifying a Postmortem Debugger
To set the postmortem debugger to WinDbg, run windbg -I. (The I must be capitalized.) This command will display a success or failure message after it is used. When WinDbg is the postmortem debugger, it will be activated whenever an application crashes.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 11 Noviembre 2014, 01:29 am
Estoy con Eternal, no parece gran cosa...
Ya se que sera al final una tonteria... pero es que nunca he tenido que utililar herramientas tan complejas para depurar.

Bueno kub0x he estado toda la tarde trasteando, googleando, leyendo la documentacion de windows... bueno he estado tambien testeando con programas que fallaban a posta y recogiendo las excepciones y bueno este es el codigo que he empleado para recojerlas:

Código
  1. LONG WINAPI MyUnhandledExceptionFilter(_EXCEPTION_POINTERS *e)
  2. {
  3.    cout << e->ExceptionRecord->ExceptionAddress << endl;
  4.    cout << e->ExceptionRecord->ExceptionCode << endl;
  5.    cout << e->ExceptionRecord->ExceptionFlags << endl;
  6.    cout << e->ExceptionRecord->ExceptionInformation << endl;
  7.    cout << e->ExceptionRecord->NumberParameters << endl;
  8.  
  9.    system("pause");
  10.  
  11.    return EXCEPTION_EXECUTE_HANDLER;
  12. }

Haber el comando "pause" se debe a que el codigo lo tengo que ejecutar varias veces porque no siempre crashea, es depende como le pille, aunque la mayotia de veces si crashea y para dificultar las cosas cuando se esta depurando no crashea, vamos que mi propio codigo me esta vacilando como quien dice -,-"

Bueno la salida es esta:
Código
  1. 0x77340b8f
  2. 3221225477
  3. 0
  4. 0x28f6b0
  5. 2
  6. Presione una tecla para continur...

Bueno, la segunda linea es la que he visto interesante, 3221225477 que en hx es 0xC0000005 y segun winbase.h equivale al codigo EXCEPTION_ACCESS_VIOLATION, es decir el mismo codigo que cuando llamo al metodo de un objeto puntero que apunta a NULL. Aun asi he buscado en internet lo referente a este error y no viene nada en ningun lado...

¿Como averiguo que esta pasando?¿Vale ya se que excepcion salta y ahora qué si no se que la provoca?


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 11 Noviembre 2014, 02:15 am
¿Como averiguo que esta pasando?¿Vale ya se que excepcion salta y ahora qué si no se que la provoca?

Viendo la pila; esto tiene pinta de corrupcion de memoria por lo que comentaste de new y por la direccion que huele a API. Application Verifier (http://www.microsoft.com/en-us/download/details.aspx?id=20028l) puede ayudar mucho a simplificar la investigacion, dependieno del problema de origen es capaz de detectarlo incluso antes de que termine por explotar ...

Haber el comando "pause" se debe a que el codigo lo tengo que ejecutar varias veces porque no siempre crashea, es depende como le pille, aunque la mayotia de veces si crashea y para dificultar las cosas cuando se esta depurando no crashea, vamos que mi propio codigo me esta vacilando como quien dice -,-"

En mi anterior mensaje te deje la forma para que, sin tocar tu codigo, se abra automaticamente el depurador (WinDbg) cuando se produzca la excepcion.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kub0x en 11 Noviembre 2014, 02:49 am
@kafok: si tienes los símbolos de debug (pdb) podrías utilizar SymInitialize y SymFromAddr con StackWalk para recorrer la pila y detectar en que funciones ha ido fallando, es decir, todavía te falta code (pero vas pillando el concepto).

Si quieres resultados rápidos la forma de Eternal Idol es la más recomendable, ya que él te ofrece un mecanismo por el cual filtrar todas las excepciones no controladas mediante windbg.

Una vez en windbg

[..] cuando de la excepcion usa kb ffff para ver la pila (ALT+6 para la ventana), dv parar las variables locales, .etc.

Saludos!


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 14 Noviembre 2014, 02:32 am
Bueno llevo unos dias investigando a tope, he cambiado de IDE ya que la ultima me estaba dando muchos problemas y tambien llevo estos dias testeando las nuevas cosas. Pues resulta que cuando copilo en este nuevo entorno resulta que se rompe pero en el delete no en el new, y digo yo ¿Por que se rompe cuando llamo a los metodos desde una dll (importada estaticamente) y no si cojo el mismo codigo y lo copilo dentro de un proyecto independiente?

Código:
[b]Nota:[/b] he sobrecargado los operadores new y delete para guardar los punteros de los nuevos objeto en un set de la api std. Esto lo hice como una especie de recolector de basura con el fin de que me avisara si se me olvida un delete porque me hace mas los test de las clases

Despues de mucho tocar el codigo, depurar, etc... resulta que es que al borrar un elemento del set es cuando rompe, new y delete funcionan bien, solo falla si quito del set el elemento que reciba delete. Pero claro, el codigo esta bien pero al aislarlo en una dll y cargarlo desde otro proyecto sin ni siquiera tocar una linea de codigo me desconcierta, ¿Por que falla en un sitio si y en otro no (reitero)?

PD: Puede que depurar esto sea facil, pero es la primera vez que me enfrento a algo que hay que mirar en tan bajo nivel :(

Por cierto, el debbuger de ahora me dice que el procesador tira la señal SIGSEV, por si sirve de algo


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 14 Noviembre 2014, 11:48 am
Con la informacion que tenemos solo podemos adivinar. Puede ser que uses diferentes heaps para reservar y liberar. ¿Estas haciendo el new desde la DLL y el delete desde el programa (o viceversa)?


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 14 Noviembre 2014, 18:58 pm
Haber, creo un objeto de mi clase con new desde el codigo de mi programa, vamos que no esta llamado desde ningun metodo ni nada por el estilo, el codigo seria tal que asi:

Código
  1. MiClase *c = new MiClase();

He de decir que new y delete son sobrecargados en una clase padre que llame Object y que debe heredarse en todas las clases hijas que quieran implementar esto, es decir "MiClase" es hija de Object. No se si esa informacion es de interes, pero la cuento por si acaso.

La intencion de esto es que pueda dejar sin liberar la memoria que yo quiera y luego cuando copile se me informe de que hay memoria no liberada que libera otra clase que es la que contiene el set. Esta clase es un singleton y tiene varios metodos entre ellos añadir y eleminar elementos del set, y uno en especial que recorre el set eleminando sus elementos y llamando al delete del objeto. Este metodo esta pensado para llamarlo al final del programa y que lo que no se haya liberado (que siga en el set) lo elimine y lo imprima por pantalla.

Si llamas al delete desde el codigo de la aplicacion se elimina el elemento del set. En la implementacion de esto cuando se llama a delete este llama a "erase" y "erase" a delete, lo se, ese problema de recursividad esta solucionado.

Entonces delete es llamado desde ese metodo y desde la aplicacion, es decir los que no llame la aplicacion los llamara el metodo. El problema que ambos tienen que hacer un al metodo erase de set del std y es esa linea la que falla.

Ahora, te pregunto una cosa, lo que he encontrado en internet todos dicen que es que el set se hayan rotos los punteros interno que usa el arbol binario de la implementacion (o por lo menos creo que funciona asi), y tu me has hablado algo de heaps, no se... me da que puede haber hay un hilo por donde tirar, ¿Que son heaps? Detallame que es lo que puede pasar con ellos.

PD: ahora espero haberte hecho una descripcion mas profunda del problema y que a si podamos llegar a una solucion



Ante todo, muchisimas gracias por la ayuda, no se que hubiera hecho yo solo...  :huh:


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 14 Noviembre 2014, 19:28 pm
No respondiste mi pregunta concretamente: ¿Estas haciendo el new desde la DLL y el delete desde el programa (o viceversa)? Se que llamas a new desde tu programa pero no si en algun caso el delete correspondiente lo llamas desde la DLL.

Allocating and freeing memory across module boundaries (http://blogs.msdn.com/b/oldnewthing/archive/2006/09/15/755966.aspx).

Code, Stack, Data y Heap en la ejecución de programas (http://latecladeescape.com/t/Code,+Stack,+Data+y+Heap+en+la+ejecuci%C3%B3n+de+programas).

Lo que puede pasar es que el heap del cual reserves no sea el mismo del cual liberes, por ejemplo si tu programa llama a new y una DLL llamada a delete.

Heap Functions (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366711%28v=vs.85%29.aspx).



Otra vez vuelvo a los metodos sencillos de analizar el problema que te deje:

1) Enabling Postmortem Debugging (http://msdn.microsoft.com/en-us/library/windows/hardware/ff542967%28v=vs.85%29.aspx)

2) Application Verifier (http://www.microsoft.com/en-us/download/details.aspx?id=20028l) puede ayudar mucho a simplificar la investigacion, dependieno del problema de origen es capaz de detectarlo incluso antes de que termine por explotar.

PD. Liberar la memoria al terminar el programa es una absoluta perdida de tiempo de procesamiento, el S.O. se encarga de esa tarea, solamente sirve para diagnosticar memory leaks (es decir para que uno vea que se olvido de liberar en su momento y lo libere justo cuando ya no sera mas usadoq, no cuando ya no sirve de nada hacerlo).


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 15 Noviembre 2014, 03:58 am
Haber estuve leyendo y estudiando los links. Yo sabia que los programas utilizaban un espacio de memoria especial para la asignacion dinamica, vamos que eso es el heap. Pero vamos, entonces cada modulo tiene un heap distinto? Es decir, si cargo una dll todos los new dentro de los metodos se crearan en su heap y los new de mis programas en su propio heap? y el heap de la dll es compartido por todas las aplicaciones que utilicen la dll?

Entonces ¿Que limitaciones tengo al usar memoria dinamica al usar una dll? No me quedo muy claro en esas paginas.

Tu pregunta: los new los llamo desde la aplicacion y los delete desde la dll, aunque eso puede cambiar, porque esta pensado que los delete que no diga yo, los haga la dll al final, aunque de momento solo lo hace la dll.

Otra cuestion: Lo que yo tengo entendio es que la memoria que no liberes se queda como basura en el sistema hasta que reinicies, eso es lo que tengo entendido como memory leak. Pero tu que dices, que la memoria que no haya liberado la libera el sistema operativo cuando termina el programa? es decir, que la memoria que se libere tiene que ser liberada en el momento en el que deja de utilizarse, que si se elimina toda al final del programa es trabajar de mas porque el sistema operativo ya los hace?

Otra vez, muchas gracias por tu tiempo


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 15 Noviembre 2014, 10:41 am
Haber estuve leyendo y estudiando los links. Yo sabia que los programas utilizaban un espacio de memoria especial para la asignacion dinamica, vamos que eso es el heap. Pero vamos, entonces cada modulo tiene un heap distinto? Es decir, si cargo una dll todos los new dentro de los metodos se crearan en su heap y los new de mis programas en su propio heap? y el heap de la dll es compartido por todas las aplicaciones que utilicen la dll?

Si, si la DLL ofrece un metodo de reserva y de liberacion usara su heap.

Entonces ¿Que limitaciones tengo al usar memoria dinamica al usar una dll? No me quedo muy claro en esas paginas.

Se libera donde se reserva, si lo vas a hacer en la DLL exporta dos funciones para hacer ambas cosas.

Tu pregunta: los new los llamo desde la aplicacion y los delete desde la dll, aunque eso puede cambiar, porque esta pensado que los delete que no diga yo, los haga la dll al final, aunque de momento solo lo hace la dll.

No, si el programa reserva en su heap tiene que liberar en su heap, no puede liberar la DLL desde el suyo o hay problemas como el que estas viendo ahora mismo ...

Otra cuestion: Lo que yo tengo entendio es que la memoria que no liberes se queda como basura en el sistema hasta que reinicies, eso es lo que tengo entendido como memory leak. Pero tu que dices, que la memoria que no haya liberado la libera el sistema operativo cuando termina el programa? es decir, que la memoria que se libere tiene que ser liberada en el momento en el que deja de utilizarse, que si se elimina toda al final del programa es trabajar de mas porque el sistema operativo ya los hace?

Si, es exactamente como te dije. Lo que tenes que hacer es liberar la memoria cuando corresponde y ese momento es exactamente cuando deja de ser necesaria, cuando ya no sera mas accedida hay que liberarla, no esperar hasta el fin de la ejecucion del proceso.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 24 Noviembre 2014, 23:54 pm
Perdon por tardar en responder, he estado ocupado con los estudios  :-(

He estado haciendo mil pruebas, haber como reacciona las dll a algunas situaciones. Quiero destacar que mi dll es cargada estaticamente. He probado new y delete en distinto sitios (tanto en el exe como en la dll) y aunque han sido inicializadas en un sitio y liberado en otro la aplicacion no presento en ningún momento anomalias, funcionó bien, se creo y liberó memoria correctamente aun siendo declarados en distintos heaps. En la documentacion de windows solo nos ofrecen la funcion GetProcessHeap() que llamada desde la dll y el exe devuelve el mismo valor, porque es el mismo proceso. Pero no hay nada relacionado con el heap de cada modulo (el heap del exe y el de la dll) lo que da a entender que cada proceso tiene su propio heap, y este es compartido por la dll y el exe. Aqui hay una contradiccion, ¿Qué he dejado pasar por alto para haber obtenido estos resultados?

He leido que si sobrecargo los operadores new y delete y customizo la asignacion de memoria en un heap que haya creado o:

Código
  1. HeapAlloc(GetProcessHeap(), 0, size);

para el heap del proceso me curo en salud porque digo exactamente donde se guarda, pero... Sí guardo en un heap que no tengo acceso, ¿La aplicacion crashearia? Es decir, si estoy accediendo al heap del proceso, si no tenia permisos para borrar nada creado alli tampoco los tengo para crearlo, digo yo.

Por favor, que alguien arregle las barbaridades que estoy soltando


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 25 Noviembre 2014, 00:45 am
El tema es que ademas de GetProcessHeap existe HeapCreate y a esta funcion llama la RTL cuando se inicializa (un proceso puede tener mas de un heap). No, si hubieran estado en diferentes heaps pasaria lo que pasa con con el siguiente codigo:

Código
  1. HANDLE anotherHeap = HeapCreate(0, 0x1000, 0x1000 * 1024);
  2. LPVOID memoryBlock = HeapAlloc(anotherHeap, HEAP_ZERO_MEMORY, 0x1000);
  3. HeapFree(GetProcessHeap(), 0, memoryBlock);

HEAP[heapcrash.exe]: Invalid address specified to RtlFreeHeap( 000000F1B8E00000, 000000F1B9170720 )
(de6c.ed7c): Break instruction exception - code 80000003 (first chance)

0:000> kb
RetAddr           : Args to Child                                                           : Call Site
00007fff`6ad05a8e : 00007fff`6acef650 00007fff`6acef520 000000f1`b8e00000 000000f1`b9170720 : ntdll!RtlpBreakPointHeap+0x1d
00007fff`6ad419e5 : 000000f1`b8e00000 00000000`00000000 00000000`00000000 01000000`00000080 : ntdll!RtlpValidateHeapEntry+0x5429a
00007fff`6acfbdaf : 000000f1`b8e00000 00000000`50000063 000000f1`b9170000 00007fff`6ad41706 : ntdll!RtlDebugFreeHeap+0xb9
00007fff`6ac829f8 : 000000f1`b8e00000 000000f1`b9170720 000000f1`b9170710 000000f1`b9170710 : ntdll!RtlpFreeHeap+0x7908f
*** WARNING: Unable to verify checksum for heapcrash.exe
00007ff7`9749105d : 00000000`00000001 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlFreeHeap+0x428
00007ff7`974911b8 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : heapcrash!main+0x4d [d:\src\heapcrash.cpp @ 9]
00007fff`6a8016ad : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : heapcrash!__tmainCRTStartup+0x144 [f:\dd\vctools\crt\crtw32\startup\crt0.c @ 255]
00007fff`6aca4409 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d


Se produce una excepcion no controlada; si liberaramos en anotherHeap no habria ninguna excepcion.

Y si, por logica si sobrecargas de esa manera (HeapFree tambien con GetProcessHeap por supuesto) no vas a tener problemas, siempre que se use el mismo heap para reservar y liberar un determinado bloque de memoria.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 25 Noviembre 2014, 17:02 pm
Entonces, si sobrecargo el new y delete y utilizo el GetProcessHeap() por ejemplo, para asignar la memoria y liberarla, aunque llame a new desde el exe podre liberarlo desde el dll, y viceversa? De esa forma, me ahorraria todos los poblemas que me han surgido asignando memoria. Y si creo un heap para la dll seria exactamente igual solo que podria personalizar algunas cosas no?

Muchas gracias, me estas ayudando un monton


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 25 Noviembre 2014, 17:30 pm
Si; siempre que se use el mismo heap - no importa cual - para reservar y liberar un bloque de memoria determinado no habra problemas.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 27 Noviembre 2014, 21:39 pm
Ahora tengo otro problema... he rediseñado mi proyecto de nuevo, los heap ya son correctos... pero... cuando asigno estaticamente memoria (es decir, en variables y no punteros, no se como se llama exactamente eso) me sigue dando problemas de violacion de acceso.

Mi clase tiene unos pocos de constructores, los cuales estoy testeando. Lo hice declarando un array para tener las multiples variables que cree bien situadas tal que asi:

Código
  1. MiClase clase[64];

Eso me tira error al finalizar el programa. Lo siguiente me da error cuando creo una variable desde el constructor tal que:

Código
  1. MiClase *clase = new MiClase[64];

Es decir, que en el momento que hago:

Código
  1. clase[0] = MiClase(1.0f)    //Por ejemplo

Crashea con el mismo error. Solo funciona de forma "estatica" (como yo lo llamo) si son variables independientes, es decir, no arrays.

Mi duda ahora es, tengo alguna limitacion para asignar a este tipo de variables desde una dll? de ser asi, ¿Como limito al usuario para que solo pueda usar new para crear objetos (no de forma "estatica")? Bueno, lo mismo es que yo este haciendo algo mal y no tengo ningun tipo de limitaciones  :-X


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 27 Noviembre 2014, 22:47 pm
El problema es tu codigo, puede ser un constructor, un metodo o un destructor, vaya uno saber,  no tenemos el codigo. Te lo digo nuevamente: descarga, instala y usa el Application Verifier.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 28 Noviembre 2014, 00:00 am
Creo que se lo que pasa....

1) No se usar Application Verifier: Si, descargue el sdk de depuracion de windows cuando me lo dijo. He estado utilizando el WinDbg, y he estado intentando comprender el Application Verifier pero no soy capaz... haber cojo la aplicacion cargo mi programa y selecciono los test en la derecha y pulso save. Despues, ¿Usa el depurador de mi IDE, o como va eso?

2) Creo que se donde esta el problema: Me imagino que al hacer new y tenerlo sobrescrito para que guarde la memoria en el heap que le diga, los atributos de mis clases que no sean punteros se guardaran en dicho heap, pero ¿y cuando no uso new para inicializar el objeto?¿Donde se guarda ese atributo? Creo que ese es el problema, que se guarda donde no debe.

Entonces, si fuera ese el problema podria solucionarlo creando los atributos de forma dinamica, pero para el atributo que me da problemas uso una clase del std, string. Entonces ahora me surgen las siguientes dudas:

    -¿Como asigno al heap que yo quiera una clase de la que puedo sobrescribir el operador new? Es decir, ¿como guardo un objeto string en mi heap?

    -Si declarara el resto de atributos de mis clase a partir de punteros y los inicializara en el constructor y liberara en el destructor, si declaro una variable "estatica", como yo las llamo, de esa clase, al finalizar el ambito de esa varible ¿Se llamaria al destructor y liberaria esa memoria asignada o se liberara al finalizar el programa?

    -Y por ultimo, ya por curiosidad, una variable que no es un puntero, es decir, que no se inicializa con new ¿Como se llama eso? Yo las llamo inicializadas estaticamente, porque de otra forma es dinamicanmete, pero no se la terminologia real  :P


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 28 Noviembre 2014, 00:13 am
1) No se usar Application Verifier: Si, descargue el sdk de depuracion de windows cuando me lo dijo. He estado utilizando el WinDbg, y he estado intentando comprender el Application Verifier pero no soy capaz... haber cojo la aplicacion cargo mi programa y selecciono los test en la derecha y pulso save. Despues, ¿Usa el depurador de mi IDE, o como va eso?

Simplemente ejecuta tu programa con WinDbg, ahi veras excepciones no controladas especialmente lanzadas por el Application Verifier al detectar errores.


PD. Lo siento pero ya no voy a seguir usando mi bola de cristal: o lo depuras vos mismo o subis un minidump - y de paso el PDB - para que lo haga otro.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 2 Diciembre 2014, 02:16 am
Siento mucho haber abierto otro hilo... Cuando mas o menos supe donde estaba el problema pense que debia ponerlo en otro hilo. Haber es que soy bastante principiante en temas de depuracion y me siento un poco perdido. Intente hacer al pie de la letra lo que me dijiste que hiciera con WinDbg y Application Verifier, pero aun asi no supe solucionarlo. No me gusta la idea de que otro usuario lo haga por mi, porque me gustaria aprender a hacerlo y sobretodo no me gusta la idea de comprometer a nadie, pero para ser sinceros me harian un gran favor, pero por favor expliqueme con detalle como genero el minidump y el PDB, subo el exe y el codigo si hace falta, y como y donde lo subo, ya he dicho que soy muy novato y aun no domino muchas cosas. Muchas gracias de antemano


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 2 Diciembre 2014, 11:03 am
Siento mucho haber abierto otro hilo... Cuando mas o menos supe donde estaba el problema pense que debia ponerlo en otro hilo.

Si realmente sabes donde esta el problema lo mejor para todos es que lo reduzcas a la minima expresion y lo publiques (de esa manera no solo no nos tendras que dar tu trabajo completo sino que ademas sera mas sencillo analizar el problema al quitar todo lo superfluo).

Haber es que soy bastante principiante en temas de depuracion y me siento un poco perdido. Intente hacer al pie de la letra lo que me dijiste que hiciera con WinDbg y Application Verifier, pero aun asi no supe solucionarlo. No me gusta la idea de que otro usuario lo haga por mi, porque me gustaria aprender a hacerlo y sobretodo no me gusta la idea de comprometer a nadie, pero para ser sinceros me harian un gran favor, pero por favor expliqueme con detalle como genero el minidump y el PDB, subo el exe y el codigo si hace falta, y como y donde lo subo, ya he dicho que soy muy novato y aun no domino muchas cosas. Muchas gracias de antemano

Si lo queres hacer por tu cuenta te puedo recomendar dos libros "Inside Windows Debugging" de Tarik Soulami y "Advanced Windows Debugging" de Mario Hewardt y Daniel Pravat.

¿Que IDE usas? El PDB suele ser generado automaticamente por VC++. Para generar un dump podes usar el mismo WinDbg con el comando .dump, en la ayuda explica detalladamente los modificadores pero podrias empezar con /f.

¿Como lo subis a Internet? Amigo, busca en Google.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 2 Diciembre 2014, 14:23 pm
Si lo queres hacer por tu cuenta te puedo recomendar dos libros "Inside Windows Debugging" de Tarik Soulami y "Advanced Windows Debugging" de Mario Hewardt y Daniel Pravat.

Muchas gracias por la recomendacion, la estudiare :)

¿Que IDE usas? El PDB suele ser generado automaticamente por VC++. Para generar un dump podes usar el mismo WinDbg con el comando .dump, en la ayuda explica detalladamente los modificadores pero podrias empezar con /f.

Uso CodeBlocks. El PDB es eso de las simbolos de mi programa? Yo para generar los simbolos uso en la configuracion del copilador la bandera -g. Aun asi estudiare como hacer eso.

¿Como lo subis a Internet? Amigo, busca en Google.

Lo preguntaba porque puedo dejar enlaces a mega o a dropbox, pero en un muchos foros no puede hacerse eso, por temas de seguridad. Solo queria asegurarme de como lo puedo hacer

Entonces, ¿Dejo un link en este post cuando lo tenga todo no?¿O sino, como lo hago?


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 2 Diciembre 2014, 15:20 pm
Uso CodeBlocks. El PDB es eso de las simbolos de mi programa? Yo para generar los simbolos uso en la configuracion del copilador la bandera -g. Aun asi estudiare como hacer eso.

Yo trabajo solo con las herramientas de Microsoft pero buscando en Google encontre este metodo (no hagas el paso del strip):

http://blog.morlad.at/blah/mingw_postmortem

Lo preguntaba porque puedo dejar enlaces a mega o a dropbox, pero en un muchos foros no puede hacerse eso, por temas de seguridad. Solo queria asegurarme de como lo puedo hacer

Entonces, ¿Dejo un link en este post cuando lo tenga todo no?¿O sino, como lo hago?

Las reglas prohiben publicar enlaces a programas compilados, no hace falta en este caso, solo se necesita un dump y los simbolos de depuracion (archivo .PDB) para empezar.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 3 Diciembre 2014, 01:03 am
He hecho lo que e podio, aunque la pagina esa es de lo mejorcito que he encontrado por google para este tema, no he conseguido generar el PDB desde mi exe, ese programa falla. El tema del dump he hecho lo que he podido. Asi que, paso el codigo de donde esta el problema y nada mas, los dump que he podido generar y un archivo con detalle de lo que he hecho. Entiendo que valla contra las normas, por motivos de seguridad o por lo que sea, pero en el archivo de texto hay un link donde estan el exe compilado con la dll compilada, ambos generados con informacion de depuracion que no he podido aislar. He pasado el codigo de los archivos esos asi que solo he puesto el link por si es necesario, pero pueden generarse a partir del codigo que doy.

https://mega.co.nz/#!CYtFSZja!5DQ8DNqf07Sl2mmvMW2IzO2IiAUjValG_TduohfejQI (https://mega.co.nz/#!CYtFSZja!5DQ8DNqf07Sl2mmvMW2IzO2IiAUjValG_TduohfejQI)


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 3 Diciembre 2014, 02:08 am
Código
  1. Miclase ass[21];

El ejecutable tiene una definicion diferente de Miclase (sin miembros) que la de la DLL - algo que no se podia asumir del codigo que dejaste anteriormente - y al instanciar los objetos usa un tamaño erroneo, teniendo el string definido como en la DLL funciona correctamente.



Si queres seguir ocultando la implementacion te recomiendo leer este articulo e implementar la interfaz abstracta:
HowTo: Export C++ classes from a DLL (http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL).

Otra opcion:
http://en.wikipedia.org/wiki/Opaque_pointer#C.2B.2B


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 3 Diciembre 2014, 22:44 pm
Pffff.... al fina que tonteria era, yo creia (habia leido) que los al quitar los privates en este tipo de situaciones no pasaba nada porque al cliente solo le interesa la interfaz por asi decirlo, pero no...

Lo que propone esta pagina su primera sugerencia lo tuve en mente a la hora del diseño de mi libreria, incluso tenia un diseño pensado para hacerle al usuario mas ameno todo en vez de tener que importar a mano la funciones que devuelvan los objetos, pero, pierdo la herencia entre clases de mi dll y clases del cliente que cree mi cliente heredando de la clases, eso no seria posible, ni tampoco casting a traves de constructores, cosas de las cuales no puedo prescindir segun las necesidades de mi problema en cuestion.

Lo primero que se me ocurrio al ver el problema, y conociendo las posivilidades que tengo es obtener el tamaño de la clase con sizeof y declarar en el (.h) del cliente como privado algo tal que:

Código
  1. private:
  2.    char size[/*Aqui lo que devuelva sizeof*/];

Pero la verdad, es bastante chapucero, y tendria que tener cuidado, no es bueno trabajar con numeros magicos. La segunda opcion no la conocia, esta claro que es mi salvacion!! Pero haber entiendo que la parte que pone:
Código
  1. * : smile(new CheshireCat())


sea equivalente a poner:
Código
  1. smile = new CheshireCat();

como primera linea en el constructor de turno, pero esto:
Código
  1. : smile(new CheshireCat(*other.smile))

Es en el constructor copia, el compilador genera automaticamente un constructor copia para el struct?

Ante todo, muchisimas gracias Eternal Idol, no hubiera llegado yo solo a todas esas conclusiones por desconocimiento. Gracias


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 3 Diciembre 2014, 23:19 pm
http://en.cppreference.com/w/cpp/language/initializer_list

El constructor copia es equivalente a:
Código
  1. Handle::Handle(const Handle& other)
  2. {
  3.    smile  = new CheshireCat(*other.smile);
  4.    // do nothing
  5. }

http://en.wikipedia.org/wiki/Copy_constructor

Si, pero ese constructor copia implicito como explica en el enlace de arriba tendria el problema del shallow copy, por eso esta implementado.

Por ejemplo, esto explotaria al llegar al destructor de Handle con el objeto x donde intentaria liberar smile (que apuntaria a la memoria ya liberada al llamar al operador delete con el objeto p).
Código
  1. Handle *p = new Handle;
  2. Handle x = *p;
  3. delete p;

De nadas  ::)


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 4 Diciembre 2014, 22:07 pm
Y vuelven los problemas, aqui hay sitio para todos! vale, no!

Redefini la clase Miclase de la siguiente forma:

Código
  1. class DLL_EXPORT Miclase
  2. {
  3.    private:
  4.        struct OpaquePointer;
  5.        OpaquePointer *op;
  6.  
  7.    public:
  8.        Miclase();
  9.        ~Miclase();
  10. };

y en el .cpp:

Código
  1. struct Miclase::OpaquePointer
  2. {
  3.    string str;
  4. };
  5.  
  6. Miclase::Miclase() : op(new OpaquePointer())
  7. {
  8.    op->str.clear();
  9. }
  10.  
  11. Miclase::~Miclase()
  12. {
  13.    delete op;
  14. }

y mi codigo cliente:

Código
  1. int main()
  2. {
  3.    Miclase ss[21];
  4.    ss[0] = Miclase(); /* AQUI! */
  5.    system("pause");
  6.  
  7.    return 0;
  8. }

La linea que señalo es la que me da problemas, en mi codigo uso la funcion que me recomendaros en este hilo hace tiempo: SetUnhandledExceptionFilter. Y me salta la excepcion, pero si no pongo nada como es el caso del codigo de arriba habria que depurar para darse cuenta de que se lanza una excepcion. La excepcion salta en el destructor del elemento al que se le vuelve a llamar un construnctor por defecto. Depurando paso a paso con mi IDE, en esa linea confilctiva se llama al destructor y se vuelve a construir el nuevo. Si quito la linea y miro para otro lado no pasaria nada, pero hay hay un problema y no se cual es.

Tambien he intentado usar HeapAlloc en vez de new para OpaquePointer pero cada vez que hago alguna operacion con str como el clear crashea, eso si me imagino que habra que personalizar un Allocator pero no estoy seguro de porque falla, solo es una suposicion.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 4 Diciembre 2014, 22:55 pm
ss[0] = Miclase();   /* AQUI! */

No entiendo para que haces eso sinceramente ... ya tenes 21 objetos inicializados correctamente ... ¿Queres crear un objeto temporal y asignarlo/copiarlo en el primer elemento del array? Para que no falle sobrecarga el operador de asignacion como muestra el ejemplo ...

PD. Quiero creer que estas incluyendo la unica definicion que mostras tal cual en el ejecutable.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 5 Diciembre 2014, 19:29 pm
Ese codigo era de un test de hace tiempo, lo hice asi porque para probar despues constructores con new solo tenia q poner asterisco en la declaracion y poner el new delante asi: ss[0] = new Miclase();

Vale, al tiempo me di cuenta de que el constructor por defecto ahi era una tonteria, pero bueno, resulto que por el simple hecho de estar ahi falla. Se supone que tiene que fallar? Si es asi, ¿Como debo sobrecargar el operadir de asignacion?

Y que hago para que no falle con HeapAlloc, en vez de new,¿Tengo que definor un Allocator o que? Me interesaria tenerlo todo en el mismo heap.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 5 Diciembre 2014, 21:22 pm
Si, pero eso si tiene sentido, si uno tiene punteros a objetos entonces tiene que crear los objetos ...

En fin, en el articulo de la Wikipedia esta sobrecargado, aca tenes las declaracion para tu clase, implementalo en base al articulo:

Código
  1. Miclase& Miclase::operator=(const Miclase &other);

No se que otro fallo tendras ahora, en el ultimo codigo que dejaste con la sobrecarga mencionada no hay ningun fallo.


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: kafok en 6 Diciembre 2014, 01:17 am
aaaaaaaaa!! vale vale, sobrecargue el operador = tal y como dice la pagina, ya entiendo todos los errores que me salian. Es que no entendi muy bien porque sobrecargaba ese operador en la pagina, lo estuve mirando con calma y ya entendi el porque sobrecargarlo, y ya se porque fallaba en ese fragmentito de codigo y mas fallos que daba en mi programa real.

Ya funciona bien!! mi dll ya no da problemas!! a costado, pero al fin fucnionaaaaa!!

Muchisimas gracias


Título: Re: Como puedo depurar un fallo de asignacion de memoria en C++???
Publicado por: Eternal Idol en 6 Diciembre 2014, 10:36 am
De nadas  ::)