Entwicklung in C - Institute of Computer Engineering

Werbung
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
Herunterladen