Llamada a system() y memory leak

dagavi

En un programa en C++ que estoy realizando he detectado (o más bien me han detectado) un memory leak. Efectivamente, el programa no para de chupar memoria.

Todas las estructuras que utilizo para almacenar objetos son de la STL (map, list...) y no hago uso de memoria dinámica, excepto en un pequeño punto que si hago un new pero siempre se realiza el delete, el problema no está allí. He comprobado también que el problema no está en que lleno las estructuras que uso sin vaciarlas haciendo que no se usen (el programa hace uso de la pcap y guardo información de paquetes, he hecho que no guarde nada y sigue chupando la memoria).

Finalmente me parece haber podido detectar el leak en el siguiente método:

bool NetManager::changeChannel(unsigned short channel) const {
    //std::stringstream ss;
    //ss << "iwconfig " << monInterface << " channel " << channel << " > /dev/null 2> /dev/null";
    //ss.str().c_str();
    system("iwconfig mon0 channel 13 > /dev/null 2> /dev/null");
    return channel == 13;
}

El código, obviamente, era diferente, pero he ido modificándolo para ver si daba con que realiza el leak, llegando al punto de que me parece haber detectado que es el código que hay ahora mismo, por lo tanto es la llamada a "system()"

Memoria usada con el código de esta forma

Si quito el system la memoria se mantiene

Memoria usada dejando solo el return

¿Alguien se le ocurre que coño puede estar pasando?

LOc0

Como en otras ocasiones, no puedo solucionarte el problema, pero a ver si puedo orientarte para avanzar un poquillo... Dos pruebas más para ir descartando:

1º) Deja el system pero que llame a otro comando (por ejemplo: ping sin argumentos)

2º) Hazte un programa chorra que haga esa llamada a system un montón de veces a ver si acaba petando la memoria.

Luego vuelvo. Suerte!

Salu2 ;)

Edito: aunque seguramente no tenga que ver prueba a lanzar el iwconfig sin redirección de ficheros y/o con iwconfig mon0 channel 13 &> /dev/null

1 respuesta
dagavi

#2 He realizado el programa while (true) system() y la memoria no parecía que se moviera.

Y después de dejar el programa (solo con return) un buen rato ya va con estos datos
91 40740 1688 1388
156 40872 1688 1388
75 41004 1688 1388
79 41004 1932 1400
120 41136 1932 1400
102 42160 1932 1400
312 42160 2196 1400
312 42160 2460 1400
313 42160 2724 1400
170 42160 2988 1400
140 43184 3132 1400

Por lo que parece que el leak sigue en algún lado, y no es el system ni el stringstream -.-
Intentaré seguir quitándole cosas al programa a ver si en algún momento para de chupar memoria, espero que no sea la libpcap que no puede procesar todos los paquetes, pero me extrañaría mucho (al fin y al cabo, muchos programas lo usan sin problemas, y yo filtro para obtener solo beacons wifi)

Si encuentro algo ya pondré como lo he localizado por si le sirve a alguien en un futuro xD (aunque sea la metodología que he seguido para buscarlo). Es que lo raro es tener el leak en un programa donde no hago news (solo uno para un sistema de eventos pero siempre se borran, está asegurado). Y encima he hecho que no se guarde información de los paquetes (por lo que tampoco es que se llenen, etc.). Al desactivar lo de los eventos la interfaz gráfica no se actualiza, por lo que una mala programación de esta tampoco creo que sea (no se vuelven a llamar sus funciones para actualizarla, se queda "congelada" con el estado inicial).

Aunque está un pelín modificado, el código que estoy realizando se puede ver en https://github.com/dagavi/wmon

Ya he preguntado varias veces cosas por aquí (la captura de las beacons, y algo más), es un monitor de redes wifi que da una métrica de la utilización de la red (que sale de unas investigaciones de los que me lo han pedido).

LOc0

Es que lo del system era muuuuuuuy raro ;) A ver si hay suerte y lo encuentras. Este tipo de "fallos" son muy rallantes. Una buena idea es llevar un control de versiones o algo así para poder dar marcha atrás con seguridad, pero al final el tiempo da para lo que da. ¿Es tu PFC, no? ¡ánimo pues! Y documenta todo lo que puedas que siempre le vendrá bien a alguien (a lo mejor hago algo con libpcap para el TFM...)

Salu2 ;)

1 respuesta
dagavi

#4 Si, el desarrollo de la aplicación me valdrá como PFC.

Me comentó un profesor que buscaban a alguien para hacer ese programa, que tenían esas investigaciones y que ya las habían proba con un PFC anterior, que lo implementaba de forma muy sencilla y lo único que hace es, de una red configurada en código (poner el bssid y compilar para crear el filtro pcap y que solo pasen las beacons de la red indicada) hacer los cálculos de la utilización (% de beacons que llegan con retraso, aunque también se calculan las que se pierden).

Este nuevo que me propusieron es hacer un programa para monitorizar todas las redes (no solo una) y que tenga que ser amigable para los usuarios (estoy también realizando una interfaz en Qt, bastante simple, que muestra lo mismo que la interfaz ncurses de consola), así como fácil de instalar (con un deb no hay mayor complicación en sistemas debian).

Por esto último, de fácil de instalar, pregunté otra vez lo de compilar en modo estático (para tener un simple ejecutable), pero al final me di por vencido. La pcap y iw (creo que eran estas dos librerías) no les da la gana de compilarse completamente estático. Incluso intenté compilando yo mismo la pcap (y probando en un programa de prueba que solo usa pcap) y nada.

De documentación lo que he realizado ha sido comentar todos los .h en formato Javadoc para poderlo exportar con Doxygen, y algun comentario en los .cpp en cosas que veía que podría ayudar (incluso a mi mismo). Si bien en la documentación de los .h tendría que poner algo más como algún pre-requisito de alguna función, o que atributos modifica, como post-condición (en alguna lo he puesto, en otras no).

Tiraré para atrás en el SVN que me dejaron (en el github solo hay una versión) a ver si antes de poner la interfaz de consola ya estaba el problema, al menos me permitirá ver si es algo que pasa desde el principio o a partir de ese punto.

dagavi

Ostias, creo que al fin lo tengo, después de horas mirando que puede ser creo que al final he dado con el problema, y como no, el error está en el único sitio donde gestiono memoria dinámica xD

El problema no es como hago new o delete.

Tengo una clase GUIEvent con un solo método virtual puro: void execute() = 0;
¿Que pasa? Al manejador de eventos se envían, obviamente, subclases: registerEvent(new EventTal(args con info));

El manejador de eventos trabaja con polimorfismo, ejecuta correctamente el execute y hace un delete. ¡Aquí está el error! ¡No he puesto el destructor virtual en la superclase! Por lo que el delete se deja un montón de memoria por allí.

Edit: Aunque puede que el problema realmente esté en como uso la ncurses (si dejo el botón F11 que hace un pantalla completa - restaurar, al cabo del rato peta)

Edit2: Pues parece ser que si era lo del destructor virtual, ahora parece que la memoria no pasa de un límite:

 10 40784 1724 1420
  6 40784 1772 1464
  1 40784 5976 5656 <-- Puse la consola a modo pantalla completa, supongo que requerirá más espacio
  4 40916 5976 5656
 12 40916 5988 5664
 10 40916 6052 5664
250 40916 6064 5672
  4 41940 6064 5672
557 41940 6068 5672

2513 41940 6072 5672 <-- Lleva la tira sin consumir más espacio, como véis 2513 muestras de top -b

LOc0

Destructores virtuales... Para que luego digan que C++ es como Java con punteros xD.

Salu2 ;)

Usuarios habituales

  • LOc0
  • dagavi