Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 25 Sicheres Programmieren
  gp 25.1 Buffer Overflow (Speicherüberlauf)
    gp 25.1.1 Speicherverwaltung von Programmen
    gp 25.1.2 Der Stack-Frame
    gp 25.1.3 Rücksprungadresse manipulieren
    gp 25.1.4 Gegenmaßnahmen zum Buffer Overflow während der Programmerstellung
    gp 25.1.5 Gegenmaßnahmen zum Buffer Overflow, wenn das Programm fertig ist
    gp 25.1.6 Programme und Tools zum Buffer Overflow
    gp 25.1.7 Ausblick
  gp 25.2 Memory Leaks (Speicherlecks)
    gp 25.2.1 Bibliotheken und Tools zu Memory Leaks
  gp 25.3 Tipps zu Sicherheitsproblemen


Galileo Computing - Zum Seitenanfang

25.2 Memory Leaks (Speicherlecks)  downtop

Wie bei Buffer Overflows sind auch Memory Leaks in den meisten Fällen durch Programmierfehler zu erklären. Der erste Verdacht, es könnte sich bei Memory Leaks um Hardwareprobleme handeln, täuscht.

Ein Memory Leak entsteht, wenn ein Programm dynamisch Speicher allokiert (malloc(), realloc(), ...) und diese Speicherressourcen nicht mehr an das System zurückgibt (mittels free()). Es steht nicht unendlich viel Speicher vom Heap dafür zur Verfügung.

Programme wie das jetzt folgende erzeugen keine Probleme, wenn der Speicher nicht mehr an den Heap zurückgegeben wird:

/* mleak1.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
   char *p;
   p = (char *)malloc(sizeof("Hallo Welt\n"));
   if(NULL == p) {
      fprintf(stderr, "Abbruch: Speichermangel !!\n");
      return EXIT_FAILURE;
   }
   strcpy(p, "Hallo Welt\n");
   printf("%s",p);
   return EXIT_SUCCESS;
}

Hier bekommt der Heap seinen Speicher bei Beendigung des Programms sofort wieder zurück.

Was ist aber mit Programmen, die dauerhaft im Einsatz sein müssen? Ein gutes Beispiel sind Telefongesellschaften, die jedes laufende, eingehende und ausgehende Gespräch nach dem FIFO-Prinzip auf dem Heap ablegen und ständig für diese Datensätze Speicher auf dem Heap allokieren bzw. für ältere Datensätze wieder freigeben müssen.

Ein (stupides) Beispiel:

/* mleak2.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   char *p;
   while(p = (char *)malloc(64000)) {
      if(NULL == p) {
         fprintf(stderr, "Speicherplatzmangel!!\n");
         return EXIT_FAILURE;
      }
      /* Tu was mit dem reservierten Speicher */
   }
   return EXIT_SUCCESS;
}

Dieses Programm wird wohl eine Weile ohne Probleme laufen. Aber umso länger das Programm läuft, umso mehr Speicher benötigt es vom Heap. Dies wird sich auf Dauer schlecht auf die Performance des Systems auswirken. Denn der Heap ist ja nicht nur für ein Programm allein da. Die anderen Programme, die ebenfalls Ressourcen benötigen, werden immer langsamer. Am Ende bleibt einem nichts anderes mehr übrig, als das System neu zu starten (abhängig vom Betriebssystem und der Art der Anwendung).

Meistens ist es aber schon geschehen, und das Programm längst fertig gestellt, wenn ein Speicherleck gefunden wird. Dann kann guter Rat teuer werden, wenn Sie sich nicht auskennen.

Eine primitive Möglichkeit, sofern Sie im Besitz des Quellcodes sind, ist es, so genannte Wrapper-Makros für speicherallozierte und speicherfreigebende Funktionen zu schreiben. Beispielsweise für die malloc()-Funktion:

#define malloc(size) \
        malloc(size);\
        printf("malloc in Zeile %ld der Datei %s (%ld Bytes) \n"\
        ,__LINE__,__FILE__, size);\
        count_malloc++;

Bei Verwendung der malloc()-Funktion im Programm wird jetzt jeweils eine Ausgabe auf dem Bildschirm erzeugt, die anzeigt, in welcher Zeile, in welchem Programm und wie viel Speicher malloc() verwendet. Außerdem wird die Verwendung von malloc() mitgezählt.

Dasselbe wird anschließend auch mit der Funktion free() vorgenommen. Die Anzahl der gezählten malloc()- und free()-Aufrufe wird am Ende in eine Datei namens DEBUG_FILE geschrieben.

/* mem_check.h */
#ifndef MEM_CHECK_H
#define MEM_CHECK_H
#define DEBUG_FILE "Debug"
static int count_malloc=0;
static int count_free  =0;
FILE *f;
#define malloc(size) \
        malloc(size);\
        printf("malloc in Zeile %ld der Datei %s (%ld Bytes) \n"\
        ,__LINE__,__FILE__, size);\
        count_malloc++;
#define free(x)\
        free(x); \
        x=NULL;\
        printf("free in Zeile %ld der Datei %s\n",
               __LINE__,__FILE__);\
        count_free++;
#define return EXIT_SUCCESS; \
        f=fopen(DEBUG_FILE, "w");\
        fprintf(f, "Anzahl malloc : %ld\n",count_malloc);\
        fprintf(f, "Anzahl free   : %ld\n",count_free);\
        fclose(f);\
        printf("Datei : %s erstellt\n", DEBUG_FILE);\
        return EXIT_SUCCESS;
#endif

Hier wurde eine Headerdatei namens mem_check.h erstellt, womit alle Aufrufe von malloc() und free() auf dem Bildschirm ausgeben werden. Und zwar darüber, in welcher Datei und welcher Zeile sich ein Aufruf dieser Funktion befindet. Außerdem wird auch die Anzahl der malloc()- und free()-Aufrufe mitgezählt. Sind mehr malloc()-Aufrufe als free()-Aufrufe vorhanden, wurde auf jeden Fall ein Speicherleck im Programm gefunden. Hier ein Listing zum Testen:

/* use_mem_check.c */
#include <stdio.h>
#include <stdlib.h>
#include "mem_check.h"
int main(void) {
   char *p;
   p = (char *)malloc(sizeof("Hallo Welt\n"));
   if(NULL == p) {
      fprintf(stderr, "Speichermangel!!!\n");
      return EXIT_FAILURE;
   }
   strcpy(p, "Hallo Welt\n");
   printf("%s",p);
   malloc(1024);
   free(p);
   return EXIT_SUCCESS;
}

In der Praxis und bei größeren Projekten ist diese Version, Memory Leaks aufzuspüren, nur bedingt geeignet. Mit dem Makro return 0 habe ich es mir allzu leicht gemacht. Dies setzt nämlich voraus, dass ein Programm auch damit beendet wird. Oft haben Sie es aber mit dauerhaft laufenden Programmen zu tun.

Genauso sieht es mit der Zuordnung des allokierten und freigegebenen Speichers aus. Welches malloc() gehört zu welchem free()? Aber das Prinzip dürfte verstanden worden sein. Wenn Sie Fehler wie Memory Leaks finden wollen, haben Sie notfalls mit Wrapper-Makros eine gute Möglichkeit.

Meistens werden Sie schon eher auf eines der mittlerweile vielen Tools oder auf eine der Bibliotheken, die dafür programmiert wurden, zurückgreifen.


Galileo Computing - Zum Seitenanfang

25.2.1 Bibliotheken und Tools zu Memory Leaks  toptop

Es gibt mittlerweile eine unüberschaubare Menge von solchen Debugging Tools. Daher erfolgt hier ein kleiner Überblick mit Angabe der Bezugsquellen. Meistens finden Sie dabei auf diesen Webseiten gleich die Dokumentation für die Anwendung.

ccmalloc

Bezugsquelle: http://www.inf.ethz.ch/personal/biere/projects/ccmalloc/

ccmalloc wird mit dem C/C++-Programm verlinkt und gibt nach Beendigung des Programms einen Bericht über Memory Leaks aus. ccmalloc ist nicht geeignet, um festzustellen, ob versucht wurde, aus illegalen Speicherbereichen zu lesen.

dbmalloc

Bezugsquelle: ftp://ftp.digital.com/pub/usenet/comp.sources.misc/volume32/dbmalloc/

dbmalloc ist in einer kommerziellen und einer kostenlosen Version erhältlich. Besondere Merkmale von dbmalloc sind:

gp  Funktionsfluss, Datei und Zeileninformationen werden mit angegeben
gp  Gibt Adressen zurück (hilfreich zusammen mit Debuggern)
gp  Grenzberreichsüberprüfung
gp  Ausgabe auf die Standard-Fehlerausgabe
gp  Findet Memory Leaks

Generell wird dbmalloc, wie die meisten anderen Memory-Leaks-Tools zu einem Programm hinzugelinkt. Sie müssen also im Besitz des Quellcodes sein, um diesen neu zu übersetzen. Eine gute Anleitung in deutscher Sprache zu dieser Bibliothek finden Sie unter der URL: http://www.c-handbuch.org/

mpatrol

Bezugsquelle: http://www.cbmamiga.demon.co.uk/mpatrol/

mpatrol ist ein leistungsfähiges Tool zum Auffinden von Memory Leaks, was sich leider auf die Performance des Programms negativ auswirkt. Folgende Funktionsmerkmale stehen Ihnen dabei zur Verfügung:

gp  Ein Abbild des Stacks wird bei einem Fehler angezeigt.
gp  Datei- und Zeilen-Informationen werden mit ausgegeben.
gp  Es ist kompatibel zu dmalloc, dbmalloc, insure und purify.
gp  Es ist nicht unbedingt erforderlich, neu zu übersetzen, um seine Programme mit mpatrol zu testen.
gp  Findet alle denkbaren Fehler auf dem Heap. Fehler auf dem Stack werden nicht gefunden.

Um ein Programm mit mpatrol zu testen, ist genau wie bei den meisten anderen Tools ein Überschreiben der speicheranfordernden und freigebenden Funktionsaufrufe notwendig. Bei mpatrol können Sie dies auf zwei Arten machen: Entweder Sie linken das Programm zu der statischen oder dynamischen Bibliothek oder Sie binden diese später durch einen Aufruf von

mpatrol --dynamc ./testprog -i file

dynamisch mit in das Programm ein. Die letzte Möglichkeit funktioniert allerdings nur, wenn das Programm schon dynamisch zur Standard-C-Bibliothek übersetzt wurde und selbst dann nur auf einigen wenigen Systemen, die diesen Befehl unterstützen. Für eine deutsche Dokumentation sei auch hier wieder auf die Webseite http://www.c-handbuch.org/ verwiesen.

Es gibt außer diesen hier genannten Tools noch eine Reihe weiterer sehr guter Tools zum Auffinden von Memory Leaks. Einen guten Überblick können Sie sich auf der Seite http://www.cs.colorado.edu/~zorn/MallocDebug.html verschaffen.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de