Fehler "munmap_chunk(): invalid pointer" debuggen



  • Hi.

    Ich suche gerade einen Bug in einem komplexen Fortran Programm. Die Fehlermeldung ist ein "munmap_chunk(): invalid pointer". Natuerlich steht in der Fehlermeldung noch wesentlich mehr, aber das ist verweist im wesentlichen auf externe Bibliotheken der Art /lib64/ld-2.5.so, /lib64/libc-2.5.so, /lib64/libm-2.5.so und so weiter.

    Im wesentlichen ist klar, was hier passiert. Irgendwo wird Speicher dealloziert und dabei geht etwas schief. Ich habe die Stelle auch genau lokalisiert: Der Fehler fliegt bei der Deallozierung eines Arrays. Allerdings sieht es so aus, als ob bei dem Array alles richtig gemacht wurde. Ich habe zumindest keinen direkten Grund festgestellt, warum es wegen diesem Array Probleme geben sollte. Wenn ich das Array vom Heap auf den Stack lege, dann tritt der Fehler bei der naechsten Speicherfreigabe direkt dahinter auf.

    Ich stelle auch fest, dass der Fehler sensitiv auf die Nutzung einer Routine ist, die ueberhaupt nichts mit diesen Arrays zu tun hat und auch wesentlich frueher durchlaufen wird. Das kann natuerlich irrefuehrend sein, weil durch diese Routine vielleicht nur irgendetwas im Speicher anders angeordnet wird. Ich kompiliere mit

    -traceback -C -CB -check uninit -check pointers

    und sollte somit auf offensichtliche Probleme im Code direkt aufmerksam gemacht werden. Von diesen Checks kommt aber keine Meldung ueber irgendein Problem.

    Hattet Ihr auch schonmal einen aehnlichen Fehler? Wenn ja: An was lag es? Wie kann man an die Fehlersuche in so einem Fall gezielt herangehen? Offensichtlich ist der Ort, an dem der Fehler sichtbar wird, nicht der Ursprung des Fehlers. Selbiges gilt fuer die Variablen, bezueglich der der Fehler sichtbar wird.


  • Mod

    Hast du mal valgrind auf das Problem angesetzt?



  • SeppJ schrieb:

    Hast du mal valgrind auf das Problem angesetzt?

    Ich bin bezueglich Debuggern ehrlich gesagt nicht sehr fit. Habe kurz idb ausprobiert, bin damit aber auch nicht wirklich voran gekommen.

    Aber ich habe den Fehler (vermutlich) trotzdem gefunden. Vielleicht ist die Vorgehensweise dabei und der Fehler selbst ganz interessant, deshalb skizziere ich das hier mal.

    Also: Der Fehler ist bei der Deallozierung eines Arrays A aufgetaucht. Das wurde auch irgendwo alloziert und zwar zusammen mit einer Reihe von anderen Arrays. Ich habe mir gedacht, dass wenn mit dem Array irgendetwas kaputt gegangen ist, dass das dazwischen passiert sein muss.

    Deshalb habe ich dann ein Dummy-Array D eingefuehrt, das ich direkt vor Array A alloziert habe und auch direkt davor dealloziert habe. Ab dann ist der Fehler bei der Deallozierung von D aufgetaucht. Ich habe dann zunaechst ueberprueft, ob D genau an der Stelle alloziert werden muss, an der ich es alloziere, damit der Fehler auftaucht. Das war der Fall. Direkt vor der Allozierung von D wird Array B alloziert.

    Dann habe ich die Deallozierung von D im Programm nach oben verschoben. Da zwischen Allozierung und Deallozierung eine riesige Schleife mit jeder Menge Code war, habe ich dabei innerhalb der Schleife D an diversen Orten dealloziert und sofort wieder alloziert. Entsprechend ist der Fehler dann auch an anderer Stelle aufgetreten. So konnte ich dann das Problem auf eine andere aufgerufene Routine einschraenken, an die ich D dann auch uebergeben habe und darin dann genau so vorgegangen bin.

    Am Schluss bin ich bei einem Aufruf einer LAPACK-Routine gelandet. An die wurde Array B uebergeben, um dort die Ergebnisse der Routine reinzuschreiben. B war gross genug, damit die Ergebnisse reinpassen, aber nach der LAPACK Dokumentation haette es doch noch groesser sein sollen. Keine Ahnung, was in der Routine mit B gemacht wird, aber anscheinend wird dort etwas gemacht, das entsprechende Auswirkungen auf D hat (Die eigentlich ungenutzten Array Elemente wurden also doch fuer irgendetwas genutzt). Zumindest hat es den Fehler behoben, als ich B lokal durch ein entsprechend groesseres Array ersetzt habe und die relevanten Eintraege dann im Nachhinein in B kopiert habe. Ich will aber auch nicht ausschliessen, dass das den Fehler nur scheinbar korrigiert hat. Dafuer haette ich mir den internen Aufbau der LAPACK Routine angucken muessen.

    Bei der LAPACK Routine handelt es sich uebrigens um ssyevr und bei Array B handelt es sich um das Array, das auf der Seite dort W genannt wird.


  • Mod

    Es wäre trotzdem zu empfehlen, sich in die Benutzung vom gdb einzuarbeiten. Es gibt in dem Linuxbuch von Wendzel und Plötner eine kleine Einführung, aber die ist etwas zu popelig.
    Etwas besser ist die im Buch von Bartlett (Programming from the Ground Up) http://savannah.nongnu.org/projects/pgubook/
    Nicht zu verachten die ein oder andere Videosession auf YT wie z.B. https://www.youtube.com/watch?v=XkH7NzD_Wq4



  • nachtfeuer schrieb:

    Es wäre trotzdem zu empfehlen, sich in die Benutzung vom gdb einzuarbeiten.

    Dem stimme ich im Prinzip zu. Das Problem ist, dass ich nur sehr selten auf Fehler stoße, bei denen ich mir denke, dass die Nutzung eines Debuggers hilfreich sein würde. Ich bin mir auch nicht sicher, ob ein Debugger in diesem Fall hilfreich gewesen wäre. Ich meine, der Fehler wurde durch die falsche Nutzung einer externen Bibliothek verursacht. Dadurch hat sich das Problem letztendlich in der externen Bibliothek manifestiert. Für die habe ich noch nicht einmal Debuginformationen im Kompilat.

    Für welche Art von Bugs haltet Ihr Debugger für sinnvoll? Wie setzt Ihr Debugger in welchem Rahmen ein?


  • Mod

    Ich benutze, so wie du und aus den gleichen Gründen, eher selten einen Debugger. Wenn ich ihn brauche, dann normalerweise im Falle von Logikfehlern, weil man dann den Programmfluss und -zustand gut nachvollziehen kann. Aber Logikfehler mach ich selten 🙂

    Im Falle technischer Fehler hilft meistens bereits der Compiler (idiomatisches C++ ist toll in dieser Hinsicht 😋 ) oder, falls doch mal etwas durchkommt, reicht valgrind. Da valgrind halbautomatisch arbeitet, ist es sehr viel angenehmer, damit Fehler zu suchen und zu finden, als wenn man selber mit dem Debugger durchgeht. Auch in diesem Fall hätte es sicherlich geholfen.



  • Gregor schrieb:

    Für welche Art von Bugs haltet Ihr Debugger für sinnvoll? Wie setzt Ihr Debugger in welchem Rahmen ein?

    Eigentlich immer wenn ein Fehler nicht offensichtlich ist.
    Haltepunkt rein und Run drücken. Ich wueder das aber nicht von Hand machen wollen - dafür habe ich eine IDE die mir das ganze per simpler GUI anbietet.

    Also eigentlich ist meine Vorgehensweise bei einem Problem folgende: Kurzer Blick in den Code ob da etwas offensichtliches falsch ist und wenn nein, instant breakpoint und go. Dann steht das Programm bei der Fehlerstelle und ich habe alle Variablen Werte, Callstack, etc und fange an das Problem näher zu betrachten.



  • Shade Of Mine schrieb:

    Dann steht das Programm bei der Fehlerstelle und ich habe alle Variablen Werte, Callstack, etc und fange an das Problem näher zu betrachten.

    Hmmm. Vielleicht ist das der Punkt, warum ich nie wirklich Gefallen an einem Debugger gefunden habe: In den meisten Programmen, mit denen ich in so einem Zusammenhang zu tun habe, geht es um recht komplexe Daten. Wenn man es zum Beispiel mit Bildern zu tun hat, dann hat man da im Debugger vielleicht Zugriff auf irgendwelche großen Arrays, aber schlau wird man aus so einem Wald an Zahlen nicht unbedingt. Ich erinnere mich daran, dass ich schon mehrfach Visualisierungen eines Zwischenzustands eines Algorithmus programmiert habe, um den an entsprechender Stelle debuggen zu können. So etwas kann einem ein Debugger natürlich nicht bieten. Ich denke, für die Nützlichkeit einer ganze Reihe von Funktionalitäten eines Debuggers ist es wichtig, dass die Daten in der Form, wie der Debugger sie aufbereitet, begreifbar sind. Vermutlich gibt es aber auch eine ganze Reihe von Funktionalitäten, die davon unabhängig sind.



  • Das riecht nach einem Buffer-Overrun, finde ich... Dabei werden gerne mal versteckte Meta-Dateien von allozierten Speicherbereichen überschrieben, dann weiß der Allokator nicht mehr, was er damit anfangen soll... Ist aber nur so geraten...
    Toll ist sowas immer, wenn eine DMA-Operation Amok läuft 😉


Anmelden zum Antworten