Entwicklung in C D. Ratasich, D. Prokesch Entwicklung in C Denise Ratasich, Daniel Prokesch Institut für Technische Informatik Technische Universität Wien 13./27. Oktober 2014 1 Entwicklung in C Inhalt D. Ratasich, D. Prokesch Teil 1 (13.10.) I Programmerstellung I I Übersetzen und Linken Makefiles I Argumentbehandlung I Manpages I Fehlerbehandlung Teil 2 (27.10.) I Speicherverwaltung I I I Speicherbereiche in C Dynamische Speicherverwaltung Aufspüren und Beseitigen von Fehlern 1. Vermeidung von Fehlern 2. Statische und dynamische Programmprüfung 3. Debugging mit gdb 2 Entwicklung in C D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Teil I Argumentbehandlung Optionen/ Argumente Programmkonventionen Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung 3 Entwicklung in C Programmerstellung (Überblick) D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung 4 Entwicklung in C Programmerstellung (Überblick) D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung 4 Entwicklung in C Programmerstellung D. Ratasich, D. Prokesch I Programmerstellung Übersetzungseinheit I I Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente I Übersetzen gcc -std=c99 -pedantic -Wall -D_XOPEN_SOURCE=500 \ -D_BSD_SOURCE -g -c filename.c I Argumentübergabe I getopt() I Usage Meldung Manpages Fehlerbehandlung Genau eine C-Datei (üblicherweise .c) C-Datei bindet projektspezifische und externe Header–Dateien (.h) ein I I I Übersetzungseinheit → Objektdatei (Maschinencode) Übersetzen mit -c Aktivieren aller Warnungen (-Wall) Debuginformationen erzeugen (-g) Standard: C99 (-std=c99 -pedantic) Feature Test Macros: -D_XOPEN_SOURCE=500 -D_BSD_SOURCE I Linken I Objektdateien → ausführbare Datei I Beispiel: gcc -o myprogram a.o b.o 5 Entwicklung in C Makefiles D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung I Automatisierte Programmerstellung I Mittels Regeln spezifiziert I Standardziele (per Konvention) I make all : Erstellen des Programms (aller Programme) I make clean : Entfernen aller vom Übersetzer erzeugten Dateien Manpages Fehlerbehandlung 6 Entwicklung in C Makefiles D. Ratasich, D. Prokesch Programmerstellung I I Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Spezifizieren von Abhängigkeiten (dependencies) I I Steuern inkrementelle Übersetzung Automatisches extrahieren mit gcc -MM Verwenden von Variablen I CC (C Compiler) I CFLAGS (C Compiler Optionen) I LDFLAGS (Linker Optionen) Argumentübergabe getopt() Usage Meldung Ziel Manpages Abhängigkeiten a.o: a.c a.h b.h ↹ $(CC) $(CFLAGS) -c -o a.o a.c Fehlerbehandlung Tab Variablen 7 Entwicklung in C Makefile Tipps D. Ratasich, D. Prokesch I Programmerstellung Automatische Variablen I Ziel ($@), erste ($<) und alle ($ˆ) Abhängigkeiten I Übersetzen und Linken I Kein unnötiges Duplizieren von Variablennamen Ermöglichen implizite Regeln Makefiles a.o: a.c a.h b.h $(CC) $(CFLAGS) -c -o $@ $< Argumentbehandlung Optionen/ Argumente I Argumentübergabe Pattern-Regeln I Beispiel: %.o: %.c I getopt() I Usage Meldung I Manpages Fehlerbehandlung I Nur sinnvoll in Kombination mit automatischen Variablen Anpassen durch Verändern von Variablen wie z.B. CFLAGS In Kombination mit (evtl . automatisch extrahierten) Abhängigkeiten Weitere Tipps I Konfiguration auf der Kommandozeile: make all CC=gcc-4.7 I Markieren von Targets die kein File erstellen: .PHONY: all clean 8 Entwicklung in C Makefile Beispiel D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken CC=gcc DEFS=-D_XOPEN_SOURCE=500 -D_BSD_SOURCE CFLAGS=-Wall -g -std=c99 -pedantic $(DEFS) OBJECTFILES=a.o b.o Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe .PHONY: all clean all: myprogram myprogram: $(OBJECTFILES) $(CC) $(LDFLAGS) -o $@ $^ getopt() Usage Meldung %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< Manpages Fehlerbehandlung a.o: a.c a.h b.h b.o: b.c b.h clean: rm -f $(OBJECTFILES) myprogram 9 Entwicklung in C Shell Kommandos D. Ratasich, D. Prokesch . . . bestehen aus Programmerstellung I dem Programmnamen, oder dem Pfad zur ausführbaren Datei I Optionen (options): steuern wie das Kommando angewendet wird I Argumenten (positional arguments): Objekte, auf die das Kommando angewendet werden soll (Dateien, Verzeichnisse, etc.) Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung Beispiele: make all gcc -o myprogram a.o b.o ls -l -a /usr/local/bin /usr/bin du --human-readable --summarize . du -hs 10 Entwicklung in C Optionen D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung I Optionen vor restlichen Programmargumenten I Option Kurzform: - gefolgt von einem Zeichen I Beispiel: -c I Zusammenfassen mehrerer Optionen: -l -a → -la I Option Langform: -- gefolgt von einer Zeichenkette I Beispiel: --help I Reihenfolge der Optionen üblicherweise belanglos I Optionen dürfen in der Regel maximal einmal auftreten Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung 11 Entwicklung in C Optionsargumente D. Ratasich, D. Prokesch Programmerstellung I Optionen können ein Argument verlangen I Übersetzen und Linken Makefiles I Argumentbehandlung I Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung I Bsp. Kurzform: gcc -o myprogram a.o b.o make -f Makefile.new all Bsp. Langform: make --file=Makefile.new all Unterscheidung zwischen Optionsargumenten und (gewöhnlichen) Argumenten? Ende der Optionsliste 1. Zeichenkette ist kein Argument einer Option (d.h. folgt nicht einer Option, die ein Argument verlangt) gcc -c a.c b.c ↑ 2. entweder (a) Zeichenkette -- oder (b) Zeichenkette beginnt nicht mit - oder -rm -- -x ↑ 12 Entwicklung in C Argumentübergabe an main D. Ratasich, D. Prokesch Programmerstellung I Funktionsprototyp int main (int argc, char **argv); Übersetzen und Linken argc Anzahl der Elemente von argv argv Array von Kommandozeilenparametern (argv[0]. . . argv[argc-1]) Makefiles Argumentbehandlung Optionen/ Argumente I Argumentübergabe argv[0] ist üblicherweise Programmname oder Pfad zum ausgeführten Programm (aber nicht notwendigerweise) getopt() hallo -a arg Usage Meldung h a l l o \0 - a \0 a r ... Manpages Fehlerbehandlung I argv[argc] ist lt. Standard immer NULL 13 Entwicklung in C Argumentübergabe an main D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() I Wert von argc: Anzahl Kommandozeilenparameter + 1 I Beispiele: I hallo test →2 I hallo -a optarg -o test →5 I hallo -a optarg "-o test" →4 Usage Meldung Manpages Fehlerbehandlung 14 Entwicklung in C Optionsbehandlung: getopt D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken I Zur Optionsbehandlung im C Programm wird die Funktion getopt() verwendet1 I Parameter für getopt: argc, argv, Spezifikation der gültigen Optionen I Spezifikation von Optionen I Bsp: "a:o" I a: – Option, die Optionsargument verlangt I o – Option ohne Optionsargument I Reihenfolge irrelevant, = "oa:" Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung 1 getopt_long() unterstützt auch lange Optionsnamen 15 Entwicklung in C Verwendung von getopt D. Ratasich, D. Prokesch Programmerstellung I getopt() wird wiederholt aufgerufen I Übersetzen und Linken I Makefiles Argumentbehandlung I Optionen/ Argumente I Argumentübergabe I Gibt aufeinanderfolgend jedes der Optionszeichen zurück Ungültige Option: Fehlernachricht wird ausgegeben und ’?’ wird zurückgegeben Wenn es keine weiteren Optionszeichen gibt, gibt getopt() -1 zurück optarg enthält Optionsargument optind ist Index des nächsten Elements in argv getopt() Usage Meldung Manpages Fehlerbehandlung I Aufgaben des Programmierers: I I I I Vorkommen einer Option zählen Behandlung von ungültigen Optionen Speichern von Optionsargumenten Überprüfung der korrekten Argumentanzahl 16 Entwicklung in C getopt Beispiel D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung int c; while( (c = getopt(argc, argv, "a:o")) != -1 ){ switch( c ){ case ’a’: /* Option mit Argument */ break; case ’o’: /* Option ohne Argument */ break; case ’?’: /* ungueltiges Argument */ break; default: /* unmoeglich */ assert( 0 ); } } 17 Entwicklung in C getopt: Zählen von Optionen D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages int opt_o = 0; ... case ’o’: opt_o++; break; ... if( opt_o > 1 ) /* max. 1 Mal */ usage(); if( opt_o != 1 ) /* oder: genau 1 Mal */ usage(); Fehlerbehandlung 18 Entwicklung in C getopt: Speichern von Optionsargumenten D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages char *input_file = NULL; while( (c = getopt(argc, argv, "a:o")) != -1 ) { switch( c ) { case ’a’: /* optarg: Zeiger auf Optionsargument */ input_file = optarg; break; ... } } Fehlerbehandlung 19 Entwicklung in C getopt: Argumente D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages Fehlerbehandlung while( (c = getopt(argc, argv, "a:o")) != -1 ) { switch( c ) { ... } } /* (argc - optind): Anzahl Argumente */ if( (argc - optind) != 2) { usage(); } /* optind: Index des ersten Arguments in argv */ char *input = argv[optind]; char *output = argv[optind+1] 20 Entwicklung in C Usage Meldung D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken I Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe I Optionale Angaben durch [] gekennzeichnet hallo -a optarg [-o] arg1 I Alternative Optionen durch [x|y] gekennzeichnet hallo [-a optarg | -o] arg1 I Bedingt zulässige Optionen hallo [-a optarg [-o]] arg1 I Ein oder mehrere Vorkommen eines Arguments hallo -a optarg file... Manpages Fehlerbehandlung Syntax findet auch in Manpages Verwendung (Synopsis) I getopt() Usage Meldung Dokumentiert korrekten Aufruf I Beispiel: Usage: myprog [-n] file... 21 Entwicklung in C usage() Beispiel D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente Argumentübergabe I Bei fehlerhaftem Programmaufruf char *command= "<not set>"; int main (int argc, char *argv[]) { if (argc > 0) command = argv[0]; ... } getopt() Usage Meldung Manpages Fehlerbehandlung void usage(void) { (void) fprintf(stderr,"Usage: %s [-a file] file\n", command); exit(EXIT_FAILURE); } 22 Entwicklung in C Informationsquelle Manpages D. Ratasich, D. Prokesch Programmerstellung I Sammlung von Hilfe- und Dokumentationsseiten (manual) I Für weitere Informationen siehe make(1) I Übersetzen und Linken Makefiles Argumentbehandlung Optionen/ Argumente I I Verschiedene man-Pages mit dem gleichen Themen-Namen, z.B. Argumentübergabe I getopt() I Usage Meldung I Manpages I getopt(1): der Shell-Befehl getopt(3): die C Funktion Wichtige man-page Kapitel 1 2 3 7 Fehlerbehandlung Bedeutung: „Die Informationen finden sie in den man-pages zu make in Abschnitt 1“ Lesen der manpage unter Linux: man make bzw. man 1 make Kommandozeilenprogramme Systemaufrufe (C Funktionen) Bibliotheksaufrufe (C Funktionen) Verschiedenes Suchen in den manpages I man -k keyword bzw. apropos keyword 23 Entwicklung in C Umgang mit Fehlern D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles I Fehlermeldungen auf stderr I Rückgabewert einer Funktion immer abfragen I Argumentbehandlung I Optionen/ Argumente I Argumentübergabe Viele Funktionen liefern -1 im Fehlerfall und setzen globale Variable errno (errno(3)) Ausnahme: Bei Ausgabe auf stderr Dokumentiertes Ignorieren des Rückgabewertes: (void) fprintf(stderr, "Hallo\n"); getopt() Usage Meldung Manpages Fehlerbehandlung I Beim Auftreten eines Fehlers I I Allg. z.B. Recovery-Strategie In dieser LVA: ordnungsgemäßes Terminieren (alle Ressourcen freigeben, . . . ) 24 Entwicklung in C Umgang mit Fehlern (2) D. Ratasich, D. Prokesch Programmerstellung Übersetzen und Linken Makefiles I Aussagekräftige Fehlermeldungen I Argumentbehandlung Optionen/ Argumente Argumentübergabe getopt() Usage Meldung Manpages I I I Probleme in welchem Programm? (argv[0]) Welche Probleme? (z.B. “fopen failed”) Ursache? (strerror(errno)) Terminieren des Programms I I Freigeben von Ressourcen (z.B. temporäre Dateien) exit(): Korrekter Exitcode als Argument 3 EXIT_SUCCESS bei korrekter Beendigung 7 EXIT_FAILURE im Fehlerfall Fehlerbehandlung 25 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Teil II Speicherverwaltung und Fehlerbehebung Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung 26 Entwicklung in C Speicherverwaltung (vereinfacht) D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung 27 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Speicherverwaltung (Linux) Speicherregionen am Beispiel Linux Kernel Space Im User Mode nicht verfügbar Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Stack main() f() RLIMIT_STACK Memory Mapping Segment Dynamische Bibliotheken, Dateien, angeforderter Arbeitsspeicher Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Stack Offset (zufällig) Heap dynamisch angeforderter Arbeitspeicher BSS Segment: Uninitialisierte globale Variablen Bespiel: static int counter; Data Segment: Initialisierte globale Variablen Beispiel: static int counter = 1; Text Segment: Binärcode der ausführbaren Datei Maschinenbefehle, Konstanten brk start_brk end_data start_data end_code start_code Adaptiert von Gustavo Duartes Blog: http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory 28 Entwicklung in C Speicherverwaltung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung I Klassifizierung Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele Weiterführendes I I Vermeidung Bisher betrachtet I Fehlerbehebung I I Speicherregion: Statisch, Stack, Heap Angeforderte Größe: konstant, dynamisch Lebensdauer: Programm, Block, vom Programmierer bestimmt Statische Variablen (globale Definitionen) Lokale Variablen fester Größe (lokale Definitionen) Noch nicht betrachtet Programmanalyse I Debugging I Speicherplatz dynamischer Größe Speicherplatz mit flexibler Lebensdauer Zusammenfassung 29 Entwicklung in C Globale Variablen D. Ratasich, D. Prokesch Speicherverwaltung I Definition: Außerhalb von Funktionen oder static Modifier Klassifizierung char hello[] = "hello"; Globale und lokale Variablen void f(void) { static int keep; ... } Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung I Gültigkeitsdauer: Programm (Adresse stets gültig) I Typischer Speicherbereich: Data oder BSS I Speicherplatzbedarf ist dem Übersetzer bekannt I Initialisiert (implizit oder explizit) Vermeidung Programmanalyse Debugging Zusammenfassung I I Data: Explizit initialisierte Variablen BSS: Implizit mit 0 initialisiert 30 Entwicklung in C D. Ratasich, D. Prokesch Globale Variablen Beispiel 1 Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse char hello[] = "hello"; void f(void) { hello[0] = ’H’; /* ?? */ } OK, hello ist initialisiertes Array im Datensegment. Debugging Zusammenfassung 31 Entwicklung in C D. Ratasich, D. Prokesch Globale Variablen Beispiel 2 Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes char *hello = "hello"; void f(void) { hello[0] = ’H’; /* ?? */ } Fehlerbehebung Vermeidung Programmanalyse Speicherzugriffsverletzung, hello ist Zeiger auf String-Konstante im Textsegment. Debugging Zusammenfassung 32 Entwicklung in C D. Ratasich, D. Prokesch Globale Variablen Beispiel 3 Speicherverwaltung Klassifizierung Globale und lokale Variablen const char hello[] = "hello"; Dynamisch angeforderter Speicher void f(void) { char *ptr = hello; /* discards const qualifier */ ptr[0] = ’H’; /* ?? */ } Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Speicherzugriffsverletzung, hello ist (und bleibt) Konstante im Textsegment. Debugging Zusammenfassung 33 Entwicklung in C Lokale Variablen D. Ratasich, D. Prokesch Speicherverwaltung I Definition: In einem Anweisungsblock (C89: zu Beginn) Klassifizierung if (a > b) { int x; char c = ’A’; ... } Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes I I Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Gültigkeitsdauer: Bis zum Ende des Blocks I Freigabe des Speichers beim Verlassen des Blocks Adresse verliert Gültigkeit I Typischer Speicherbereich: Stack I Speicherplatzbedarf ist dem Übersetzer bekannt (Ausnahme: Arrays variabler Größe in C99) I Keine implizite Initialisierung (Initialwert undefiniert) 34 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 1 void g(int *x) { *x += 10; } int f(void) { int a = 1; // <-g(&a); return a; } Vermeidung Programmanalyse Debugging Address Name Value 0xffc a 1 Zusammenfassung 35 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 1 void g(int *x) // <-{ *x += 10; } int f(void) { int a = 1; g(&a); return a; } Vermeidung Programmanalyse Debugging Zusammenfassung Address Name Value 0xffc 0xff8 a x 1 0xffc 35 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 1 void g(int *x) { *x += 10; // <-} int f(void) { int a = 1; g(&a); return a; } Vermeidung Programmanalyse Debugging Zusammenfassung Address Name Value 0xffc 0xff8 a x 11 0xffc 35 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 1 void g(int *x) { *x += 10; } int f(void) { int a = 1; g(&a); return a; // <-} Vermeidung Programmanalyse Debugging Address Name Value 0xffc a 11 Zusammenfassung OK 35 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 2 int *g(int x) { int y = x + 10; return &y; } int f(void) { int *a; // <-a = g(1); return *a; } Vermeidung Programmanalyse Debugging Address Name Value 0xffc a ? Zusammenfassung 36 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 2 int *g(int x) { int y = x + 10; // <-return &y; } int f(void) { int *a; a = g(1); return *a; } Vermeidung Programmanalyse Debugging Zusammenfassung Address Name Value 0xffc 0xff8 0xff4 a x y ? 1 11 36 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Lokale Variablen Beispiel 2 int *g(int x) { int y = x + 10; return &y; } int f(void) { int *a; a = g(1); return *a; // <-} Vermeidung Programmanalyse Debugging Zusammenfassung Address Name Value 0xffc 0xff8 0xff4 a – – 0xff4 ? ? Dereferenzieren von a resultiert in undefiniertes Verhalten! 36 Entwicklung in C Stack Overflow D. Ratasich, D. Prokesch Speicherverwaltung I Klassifizierung I Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Die Größe des Stacks ist auf vielen Systemen begrenzt I Linux: ulimit -s I Symptom bei Überschreiten der Grenze: Speicherschutzverletzung Beispiel: int fib(int n) { if (n <= 1) { return 1; } else { return fib(n-1) + fib(n-2); } } ... fib(200000); 37 Entwicklung in C Dynamisch angeforderter Speicher D. Ratasich, D. Prokesch Speicherverwaltung I Anfordern und Freigeben von Speicher zur Laufzeit Klassifizierung I Globale und lokale Variablen I Dynamisch angeforderter Speicher I I I Beispiele Größe erst zur Laufzeit bekannt Lebensdauer anwendungsabhängig Keine direkte Unterstützung in C → Bibliotheksfunktionen Typischer Speicherbereich: Heap Beispiele: Einlesen von Daten variabler Länge, dynamische Datenstrukturen Weiterführendes Fehlerbehebung I Portable Bibliothek zur Speicherverwaltung – A memory allocator Vermeidung I Programmanalyse I Debugging I I Zusammenfassung Speicher wird manuell verwaltet Anfordern von Speicher beliebiger Größe: malloc(3) Freigeben zuvor angeforderten Speichers: free(3) Ändern der Größe eines zuvor angeforderten Speichers: realloc(3) 38 Entwicklung in C Anfordern von Speicher D. Ratasich, D. Prokesch void *malloc(size_t size); Speicherverwaltung /* Beispiele char *x = int *x = int *x_arr = Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher */ malloc(sizeof (char)); malloc(sizeof *x); malloc(sizeof (int) * n); typedef struct { int x, y, r; } circle_t; Beispiele Weiterführendes circle_t *circ1 = malloc(sizeof (circle_t)); circle_t *circ2 = malloc(sizeof *circ2); Fehlerbehebung Vermeidung Programmanalyse I Allokation von size Bytes zusammenhängenden Speichers I Rückgabewert: Startadresse des Speicherbereichs I Adresse identifiziert Speicherbereich I Speicher ist nicht initialisiert (vgl. calloc(3)) Debugging Zusammenfassung 39 Entwicklung in C Anfordern von Speicher D. Ratasich, D. Prokesch typedef struct { int x, y, r; } circle_t; Speicherverwaltung circle_t *circ_arr = malloc(n * sizeof (circle_t)); Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele for (int i = 0; circ_arr[i].x circ_arr[i].y circ_arr[i].r } i = = = < n; i++) { 0; 0; i+1; Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Erinnerung: pointer[index] ist äquivalent zu *(pointer + index) 40 Entwicklung in C Anfordern von Speicher D. Ratasich, D. Prokesch typedef struct { int x, y, r; } circle_t; Speicherverwaltung circle_t *circ_arr = malloc(n * sizeof (circle_t)); Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes for (int i circle_t cur->x = cur->y = cur->r = } = 0; i < n; i++) { *cur = &circ_arr[i]; 0; 0; i+1; Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung (Warum nicht nur cicle_t cur = circ_arr[i]?) 41 Entwicklung in C Freigabe angeforderten Speichers D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele void free(void *ptr); I Als Argument ptr wird entweder NULL oder eine gültige Adresse erwartet. I Eine Adresse ist gültig wenn Weiterführendes I Fehlerbehebung I Vermeidung Programmanalyse Debugging I sie von malloc(), realloc() oder calloc() zurückgegeben werde zwischenzeitlich nicht durch free() oder realloc() freigegeben wurde Kein Effekt falls ptr ein Nullpointer ist Zusammenfassung 42 Entwicklung in C Ändern der Größe des eines Speicherbereichs D. Ratasich, D. Prokesch void *realloc(void *ptr, size_t size); Speicherverwaltung Klassifizierung I Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele Weiterführendes Fehlerbehebung Erwartet gültige Adresse (wie free()) I Daten können kopiert werden, Startadresse kann sich ändern (Rückgabewert) I Falls Allokation fehlschlägt wird NULL zurückgegeben, alter Speicherbereich bleibt gültig I Spezialfälle I ptr ist NULL → verhält sich wie malloc() I size ist 0 → verhält sich wie free() Debugging Zusammenfassung Wird der Speicherbereich vergrößert, bleiben Daten erhalten Wird Speicherbereich verkleinert, bleiben die ersten size Bytes erhalten I Vermeidung Programmanalyse Ändert die Größe des durch ptr identifizierten Speicherbereichs 43 Entwicklung in C Beispiele: malloc()/free() D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele I Wie bei allen Funktionen ist der Rückgabewert zu überprüfen. Im Fall von malloc() ist dies besonders wichtig char *p; p = malloc(sizeof(char) * 6); Weiterführendes Fehlerbehebung Vermeidung Programmanalyse if (p == NULL) { bailout(); } else { strncpy(p, "hallo", 6); } Debugging Zusammenfassung free(p); /* nicht auf free vergessen! */ 44 Entwicklung in C Beispiele: malloc()/free() D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele I Freigeben dynamisch allokierten Speichers I Achtung: Nur die Startadresse darf free() übergeben werden char *p, *q; Weiterführendes Fehlerbehebung p = malloc(sizeof(char) * 6); if (p == NULL) bailout(); Vermeidung Programmanalyse Debugging p += 3; free(p); /* Fehler */ Zusammenfassung 45 Entwicklung in C Beispiele: malloc()/free() D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher I Freigeben dynamisch allokierten Speichers I Achtung: Nur die Startadresse darf free() übergeben werden char *p, *q; Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse p = malloc(sizeof(char) * 6); if (p == NULL) bailout(); p += 3; q = p - 3; Debugging free(q); Zusammenfassung /* Ok */ 46 Entwicklung in C Beispiele: malloc()/free() D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen I Freigeben dynamisch allokierten Speichers I Achtung: Nur die Startadresse darf free() übergeben werden Dynamisch angeforderter Speicher char *p, *q; Beispiele p = malloc(sizeof(char) * 6); q = p; if (p == NULL) bailout(); Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung free(p); q[0] = ’H’; /* Fehler */ Vorsicht: Alle Zeiger in den Bereich werden ungültig 47 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Beispiele: realloc() Dynamisch wachsender Stack typedef struct { int *items; unsigned capacity, top; } stack_t; void push(stack_t *st, int x) { if (st->top == st->capacity) { // need to grow int newcap = st->capacity + 10; int *newptr = realloc(st->items, sizeof(int) * newcap); if (newptr == NULL) { // error; old data (st->items) is still valid ... } st->items = newptr; // st->items was deallocated // (if it was not NULL) st->capacity = newcap; } st->items[st->top++] = x; } 48 Entwicklung in C Linux: mmap(2) D. Ratasich, D. Prokesch Speicherverwaltung I Klassifizierung Globale und lokale Variablen Bildet Dateien oder flüchtigen Speicher im Adressraum des aktuellen Prozesses ab I Dynamisch angeforderter Speicher I I Beispiele Weiterführendes Fehlerbehebung I Anwendungen von mmap() Vermeidung I Programmanalyse I Debugging Zusammenfassung Daten müssen nicht in den Adressraum des Prozesses kopiert werden Prozesse können Speicherbereiche gemeinsam verwenden Problematisch bei sehr kleinen (Verschnitt) und sehr großen (Fragmentierung des virtuellen Adressraums) Dateien I Effizientes Lesen und Bearbeiten von Dateien Effizientes Reallokieren großer Speicherbereiche (Paging-Mechanismus) Interprozesskommunikation mittels Shared Memory 49 Entwicklung in C Implementierung von malloc D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung I malloc Bibliotheksroutinen Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele Weiterführendes I Beispiel: Doug Lea’s malloc (dlmalloc)2 I Fehlerbehebung I Vermeidung Programmanalyse I Debugging Bibliothek (z.B. libc) verwaltet Speicherblöcke, die wiederum vom Betriebssystem angefordert wurden Online Algorithmus (keine Annahmen über zukünftiges Allokationsverhalten) Binning: Schnelle Allokation für kleine Blöcke, schnelle Suche für größere Blöcke Meta-Informationen in „Boundary Tag“ neben dem allokierten Speicherblock Anforderung neuen Speichers mit sbrk(2) und mmap(2) Zusammenfassung 2 http://g.oswego.edu/dl/html/malloc.html 50 Entwicklung in C On Debugging D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. – Brian Kernighan Vermeidung Programmanalyse Debugging Zusammenfassung 51 Entwicklung in C Vermeidung von Fehlern D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung I Programmierrichtlinien Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele Weiterführendes I I Style Guides (z.B. BSD Kernel) I Fehlerbehebung Vermeidung Programmanalyse Debugging Homogener, verständlicher Code Vermeidung von fehleranfälligen Konstrukten Erleichtern von automatischer Programmprüfung und Debugging I I Einheitliche Formatierung von Kommentaren und Sourcecode Regeln für Namen von Makros, Variablen und Funktionen Empfehlungen und Verbote (z.B. Pointer nicht in boolschem Kontext verwenden) für zu verwendende Konstrukte und Bibliotheksfunktionen Zusammenfassung 52 Entwicklung in C D. Ratasich, D. Prokesch Zusicherungen assert(3) Speicherverwaltung Klassifizierung Globale und lokale Variablen I Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Dynamische Überprüfung von Vorbedingungen, Invarianten (z.B. in Schleifen) und Nachbedingungen I z.B. assert(ptr != NULL)) I I Stichwort: Design by Contract Realisierung in C: assert(3) I Einbinden von <assert.h> I Deaktivieren durch gcc -DNDEBUG ... I I Programmausführung bricht bei Verletzung mit Fehlermeldung und mittels abort(3) ab (→ core dump) Zusätzliche Information: assert(expr && "Message") Zusammenfassung 53 Entwicklung in C Richtlinien für sicherheitskritischen Code D. Ratasich, D. Prokesch Speicherverwaltung I Am Beispiel des Jet Propulsion Laboratory, Caltech3 I Programmierstil Klassifizierung I Globale und lokale Variablen I Dynamisch angeforderter Speicher I Defensive Programmierung I Beispiele I Weiterführendes I Fehlerbehebung I I Vermeidung I I I Zusammenfassung I 3 großzügiges Verwenden von Zusicherungen Variablensichtbarkeit minimieren alle Rückgabewerte überprüfen Berücksichtigen und Beheben aller Compilerwarnungen Vereinfachen der Programmprüfung Programmanalyse Debugging Maximal eine Bildschirmseite pro Funktion eingeschränkte Verwendung des Präprozessors statisch begrenzte maximale Anzahl von Schleifendurchläufen einfache Kontrollstrukturen (kein goto, keine Rekursion) keine dynamische Speicherallokation nach Initialisierung eingeschränkte Verwendung von Zeigern G.J. Holzmann, The power of 10: rules for developing safety-critical code. Published in IEEE Computer 2006 54 Entwicklung in C Toolchain Revisited D. Ratasich, D. Prokesch Speicherverwaltung a.h Klassifizierung b.h Abhängigkeiten Globale und lokale Variablen x.c Dynamisch angeforderter Speicher Statische Analysetools Präprozessor Source Code Beispiele x.i Weiterführendes z.B. Laufzeitanalyse Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung Dynamische Analysetools Übersetzer Maschinencode Debugger x.o y.o Statische Bibliotheken Profiling Tools Linker executable Dynamische Bibliotheken Image credits: Benedikt Huber 55 Entwicklung in C Programmanalyse vs. Debugging D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung I Statische Analyse (Inspektion des Programmcodes) Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele I I Weiterführendes Vermeidung Programmanalyse Debugging Dynamische Analyse (Prüfung während des Programmablaufs) I Fehlerbehebung I I Am Source Code oder Binärdatei Einfache Form: Compilerwarnungen (-Wall, clang) z.B. splint, BLAST, viele kommerzielle Tools Instrumentiertes Programm z.B. dmalloc, valgrind Debugging (Inspektion des laufenden Prozesses) I Debugnachrichten (printf) I Interaktiv, mit Hilfe eines Debuggers (z.B. gdb) Zusammenfassung 56 Entwicklung in C Statische Analysetools D. Ratasich, D. Prokesch Speicherverwaltung I I Klassifizierung Globale und lokale Variablen I I Dynamisch angeforderter Speicher Beispiele Weiterführendes Analysieren Source Code des Programms Fehlervorbeugung I I I I I Vermeidung Programmanalyse I Zusammenfassung Zugriff auf unintialisierten Speicher Verwendung ungültiger Adressen Verletzen von Zusicherungen Beispiel: splint4 I Debugging Warnung bei fehleranfälligen Konstrukten Strengere Typregeln Fehlererkennung I Fehlerbehebung Erkennt viele typische Fehler (aber nicht alle) Häufiges Problem: falsch Positive → Desensibilisierung Zusätzliche Annotationen: Erhöhen der Treffsicherheit, stärkere Zusicherungen 4 http://www.splint.org http://wiki.vmars.tuwien.ac.at/index.php/Splint 57 Entwicklung in C Beispiel: splint D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele #include <stdlib.h> #include <stdio.h> int **f() { int *x = malloc(sizeof *x); int **y = malloc(sizeof *y); Weiterführendes *y = x; Fehlerbehebung *y = NULL; Vermeidung Programmanalyse Debugging return y; } Zusammenfassung 58 Entwicklung in C Beispiel: splint D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher #include <stdlib.h> #include <stdio.h> int **f() { int *x = malloc(sizeof *x); int **y = malloc(sizeof *y); *y = x; /* splint: Dereference of possible null pointer * */ Beispiele Weiterführendes Fehlerbehebung *y = NULL; /* splint: Owned storage *y not released * before assignment * */ return y; Vermeidung Programmanalyse Debugging Zusammenfassung } 59 Entwicklung in C Dynamische Analyse D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung I Dynamische Analysen sammeln zusätzliche Informationen während der Programmausführung I Qualität hängt daher von den Testläufen ab I Beispiel: valgrind5 Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele I Weiterführendes I Fehlerbehebung I Vermeidung Programmanalyse Framework zur Instrumentierung von Programmen Simuliert parallel zum Programm ein Modell zur Fehlererkennung memcheck: Hauptmodul um Fehler in der dynamischen Speicherverwaltung zu finden Debugging Zusammenfassung 5 http://valgrind.org/ http://wiki.vmars.tuwien.ac.at/index.php/Valgrind 60 Entwicklung in C D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Beispiel: valgrind #include <stdlib.h> int **f() { int *x = malloc(sizeof *x); int **y = malloc(sizeof *y); *y = x; *y = NULL; return y; } int main(int argc, char **argv) { if(argc != 1) return 1; Programmanalyse int **mem = f(); if (mem != NULL) { if (*mem) free(*mem); free(mem); } Debugging Zusammenfassung } 61 Entwicklung in C Beispiel: valgrind D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== ==7313== Memcheck, a memory error detector Copyright (C) 2002-2012, and GNU GPL’d, by Julian Seward et al. Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info Command: valgrind_ex HEAP SUMMARY: in use at exit: 4 bytes in 1 blocks total heap usage: 2 allocs, 1 frees, 12 bytes allocated 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x4C2A2DB: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux by 0x40058E: f (valgrind_ex.c:6) by 0x4005E2: main (valgrind_ex.c:17) LEAK SUMMARY: definitely lost: indirectly lost: possibly lost: still reachable: suppressed: 4 0 0 0 0 bytes bytes bytes bytes bytes in in in in in 1 0 0 0 0 blocks blocks blocks blocks blocks For counts of detected and suppressed errors, rerun with: -v ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2) 62 Entwicklung in C Debugging D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen I Dynamisch angeforderter Speicher Finden und Beheben der Ursache eines bekannten Programmfehlers I Modifizieren und Testen des Programms Beispiele I Weiterführendes I Fehlerbehebung Vermeidung Programmanalyse I Zusätzliche Zusicherungen (assert(3)) Debugnachrichten Mit Hilfe eines Debuggers I I Anhalten und Inspektion des laufenden Prozesses Inspektion des core dumps Debugging Zusammenfassung 63 Entwicklung in C Debugnachrichten I D. Ratasich, D. Prokesch I Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Bedingt aktivieren mit Hilfe des Präprozessors: gcc -g -DDEBUG ... I Deaktiviert: keine Performancebeinträchtigung #ifdef DEBUG #include <stdio.h> #define debug(msg) \ (void) fputs(msg, stderr) Weiterführendes Fehlerbehebung Vermeidung #else #define debug(msg) /* NOP */ Programmanalyse Debugging Zusammenfassung #endif // DEBUG ... debug("I reached this point"); 64 Entwicklung in C Debugnachrichten II D. Ratasich, D. Prokesch I Speicherverwaltung Klassifizierung Erweiterte Ausgaben mit Hilfe von vordefinierten und variadischen Makros6 Globale und lokale Variablen #define debug(fmt, ...) \ (void) fprintf(stderr, "[%s:%d] " fmt "\n", \ __FILE__, __LINE__, ##__VA_ARGS__) Dynamisch angeforderter Speicher ... Beispiele debug("x=%d", x); Weiterführendes Fehlerbehebung // gcc Warnung mit ’-std=c99 -pedantic’: debug("reached"); Vermeidung Programmanalyse I Output: Debugging [dbgmacro.c:15] x=42 [dbgmacro.c:18] reached Zusammenfassung 6 siehe http://gcc.gnu.org/onlinedocs/cpp/Macros.html, unter „Predefined Macros“ und „Variadic Macros“ 65 Entwicklung in C Debuggingwerkzeuge D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes I Inspektion eines laufenden Prozesses I Aufgaben des Debuggers I I I Fehlerbehebung Vermeidung I Anhalten des Prozesses an bestimmten Punkten Inspektion des Speichers und der Prozessorregister Aufbereiten der Informationen (Verbindung zum Sourcecode) Manipulation der Register und des Arbeitsspeichers Programmanalyse Debugging Zusammenfassung 66 Entwicklung in C GDB: The GNU Project Debugger D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher I http://www.gnu.org/software/gdb I Debugging des Maschinencodes I Vorbereitung I Beispiele Weiterführendes Fehlerbehebung I Optimierungen verkomplizieren Debugging I I Vermeidung Programmanalyse Übersetzen mit -g (Debuggingsymbole) I Eliminierte Variablen, Präprozessor-Makros Strukturelle Änderungen (z.B. durch Function-Inlining, Schleifenoptimierungen) Achtung: u.U. treten Fehler nur in optimierter Version auf Debugging Zusammenfassung 67 Entwicklung in C Starten des Debuggers D. Ratasich, D. Prokesch I Programmstart im Debugger, z.B.: I gdb myprogram und mit run [args] I gdb -args myprogram [args] und mit run I Einen Core-Dump analysieren Speicherverwaltung Klassifizierung Globale und lokale Variablen I Dynamisch angeforderter Speicher I Beispiele I Weiterführendes Fehlerbehebung bei abnormaler Prozessbeendigung In der bash-Shell müssen core dumps zuerst aktiviert werden: ulimit -c unlimited gdb -c core myprogram bzw. gdb myprogram core I An laufenden Prozess anhängen I Vermeidung I Programmanalyse I Debugging Zusammenfassung I I mittels Prozessnummer (PID) gdb myprogram und mit attach 2345 gdb myprogram 2345 falls ein Prozess mit dieser PID existiert siehe auch pidof(8), ps(1) Option -tui startet gdb mit einem textbasierten User Interface 68 Entwicklung in C Grundbegriffe D. Ratasich, D. Prokesch Speicherverwaltung I Programm bis zur nächsten Unterbrechung ausführen Spezifizieren des Programms file binary Starten des Programms run args... Ausführen nach Unterbrechung continue I Programm schrittweise ausführen Bis zur nächsten Zeile Bis zum nächsten Maschinenbefehl Wie step, überspringt Funktionsaufrufe Bis zu höherer Zeilennummer oder Funktionsende Bis zur angegebenen Stelle Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung step stepi next(i) until until x.c:30 69 Entwicklung in C Breakpoints D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen Dynamisch angeforderter Speicher I Punkte im Programm, an denen die Ausführung unterbrochen werden soll I Realisierung in HW (CPU Unterstützung) oder SW (Modifikation des Programmcodes) I Spezifizieren von Breakpoints (Achtung: Optimierungen) Datei und Zeilennummer break example.c:24 Funktionseintritt break main Bedingter Breakpoint break f if (x>3) Modifizieren disable/enable/delete Beispiele Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Debugging Zusammenfassung 70 Entwicklung in C Watchpoints D. Ratasich, D. Prokesch Speicherverwaltung I I Klassifizierung I Globale und lokale Variablen I I Dynamisch angeforderter Speicher Beispiele I I Weiterführendes Fehlerbehebung Vermeidung Programmanalyse Unterbricht Ausführung wenn sich Variable ändert Anwendungsbereiche I I I Beobachten einer Variable über längeren Zeitraum Falls unbekannt, wann sich Variable ändert Catchpoints: Ausführung wird bei Auftreten bestimmter Ereignisse unterbrochen I Debugging Zusammenfassung Realisierung in HW (bis 16 Bytes auf x86) Realisierung in SW (langsam, single stepping) watch myvar – geschrieben rwatch myvar – gelesen awatch myvar – geschrieben und gelesen I Prozessaktivitäten: catch fork, catch exec Syscalls (nicht überall verfügbar): catch syscall name 71 Entwicklung in C Inspektion des Prozesses D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen I print argc print argv[0] print/x &argc p *((int*)0xbfffff2b0)) Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung $1 $2 $3 $4 = = = = 1 "hello" 0xbfffff2b0 42 I Ändern von Speicherwerten I set variable x=0 I set (x=0) I Ausgabe bei jeder Unterbrechung mit display Vermeidung Programmanalyse Ausgabe des aktuellen Werts von C Expressions Debugging Zusammenfassung 72 Entwicklung in C GDB und Signale D. Ratasich, D. Prokesch Speicherverwaltung Klassifizierung Globale und lokale Variablen I Als „Breakpoint“ konfigurierbar I SIGINT → Kontrolle an den Debugger I Signale können selektiv an Programm weitergegeben werden I siehe info signals I z.B. handle SIGUSR1 nostop print pass Dynamisch angeforderter Speicher Beispiele Weiterführendes Fehlerbehebung Material zu GDB: I OSUE-Wiki: http://wiki.vmars.tuwien.ac.at/index.php/Gdb I Tutorial: http://beej.us/guide/bggdb/ I Manual: http://sourceware.org/gdb/onlinedocs/gdb/ Vermeidung Programmanalyse Debugging Zusammenfassung 73 Entwicklung in C Zusammenfassung D. Ratasich, D. Prokesch Speicherverwaltung I Dynamische Speicherverwaltung Klassifizierung I Globale und lokale Variablen Dynamisch angeforderter Speicher I I I Weiterführendes I Fehlerbehebung I Debugging Zusammenfassung I Programmierrichtlinien Zusicherungen Programmanalyse I Vermeidung Programmanalyse Vermeidung von Fehlern I Beispiele Speicherregionen und C Dynamische Speicheranforderung mit malloc statisch, wie z.B. mit splint dynamisch, wie z.B. mit valgrind Debugging I I Debuggingnachrichten (C Präprozessor) interaktiv, z.B. gdb 74