close

Anmelden

Neues Passwort anfordern?

Anmeldung mit OpenID

Entwicklung in C - Institute of Computer Engineering - Technische

EinbettenHerunterladen
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.)
Programmerstellung
Übersetzen und Linken
Makefiles
Argumentbehandlung
Manpages
Fehlerbehandlung
Teil 2 (27.10.)
Speicherverwaltung
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
Übersetzungseinheit
Programmerstellung
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
Manpages
Fehlerbehandlung
Genau eine C-Datei (üblicherweise .c)
C-Datei bindet projektspezifische und externe
Header–Dateien (.h) ein
Übersetzen
gcc -std=c99 -pedantic -Wall -D_XOPEN_SOURCE=500 \
-D_BSD_SOURCE -g -c filename.c
Ü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
Linken
Objektdateien → ausführbare Datei
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
Automatisierte Programmerstellung
Mittels Regeln spezifiziert
Standardziele (per Konvention)
make all : Erstellen des Programms (aller Programme)
make clean : Entfernen aller vom Übersetzer erzeugten
Dateien
Manpages
Fehlerbehandlung
6
Entwicklung in C
Makefiles
D. Ratasich,
D. Prokesch
Programmerstellung
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Spezifizieren von Abhängigkeiten (dependencies)
Steuern inkrementelle Übersetzung
Automatisches extrahieren mit gcc -MM
Verwenden von Variablen
CC (C Compiler)
CFLAGS (C Compiler Optionen)
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
Programmerstellung
Übersetzen und
Linken
Automatische Variablen
Ziel ($@), erste ($<) und alle ($ˆ) Abhängigkeiten
Kein unnötiges Duplizieren von Variablennamen
Ermöglichen implizite Regeln
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
Manpages
Fehlerbehandlung
a.o: a.c a.h b.h
$(CC) $(CFLAGS) -c -o $@ $<
Pattern-Regeln
Beispiel: %.o: %.c
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
Konfiguration auf der Kommandozeile:
make all CC=gcc-4.7
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
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
dem Programmnamen, oder dem Pfad zur ausführbaren
Datei
Optionen (options): steuern wie das Kommando
angewendet wird
Argumenten (positional arguments): Objekte, auf die das
Kommando angewendet werden soll (Dateien,
Verzeichnisse, etc.)
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
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
Manpages
Optionen vor restlichen Programmargumenten
Option Kurzform: - gefolgt von einem Zeichen
Beispiel: -c
Zusammenfassen mehrerer Optionen: -l -a → -la
Option Langform: -- gefolgt von einer Zeichenkette
Beispiel: --help
Reihenfolge der Optionen üblicherweise belanglos
Optionen dürfen in der Regel maximal einmal auftreten
Fehlerbehandlung
11
Entwicklung in C
Optionsargumente
D. Ratasich,
D. Prokesch
Programmerstellung
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
Manpages
Fehlerbehandlung
Optionen können ein Argument verlangen
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
Funktionsprototyp
int main (int argc, char **argv);
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
argc Anzahl der Elemente von argv
argv Array von Kommandozeilenparametern
(argv[0]. . . argv[argc-1])
argv[0] ist üblicherweise Programmname oder Pfad zum
ausgeführten Programm (aber nicht notwendigerweise)
hallo -a arg
h
a
l
l
o
\0
-
a
\0
a
r ...
Manpages
Fehlerbehandlung
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()
Wert von argc: Anzahl Kommandozeilenparameter + 1
Beispiele:
hallo test → 2
hallo -a optarg -o test → 5
hallo -a optarg "-o test" → 4
Usage Meldung
Manpages
Fehlerbehandlung
14
Entwicklung in C
Optionsbehandlung: getopt
D. Ratasich,
D. Prokesch
Programmerstellung
Übersetzen und
Linken
Zur Optionsbehandlung im C Programm wird die Funktion
getopt() verwendet1
Makefiles
Argumentbehandlung
Parameter für getopt:
argc, argv, Spezifikation der gültigen Optionen
Optionen/
Argumente
Spezifikation von Optionen
Bsp: "a:o"
a: – Option, die Optionsargument verlangt
o – Option ohne Optionsargument
Reihenfolge irrelevant, = "oa:"
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
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt() wird wiederholt aufgerufen
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
Aufgaben des Programmierers:
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
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Dokumentiert korrekten Aufruf
Beispiel: Usage: myprog [-n] file...
Syntax findet auch in Manpages Verwendung (Synopsis)
Optionale Angaben durch [] gekennzeichnet
hallo -a optarg [-o] arg1
Alternative Optionen durch [x|y] gekennzeichnet
hallo [-a optarg | -o] arg1
Manpages
Bedingt zulässige Optionen
hallo [-a optarg [-o]] arg1
Fehlerbehandlung
Ein oder mehrere Vorkommen eines Arguments
hallo -a optarg file...
Usage Meldung
21
Entwicklung in C
usage() Beispiel
D. Ratasich,
D. Prokesch
Programmerstellung
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
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
Sammlung von Hilfe- und Dokumentationsseiten (manual)
Programmerstellung
Für weitere Informationen siehe make(1)
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
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Verschiedene man-Pages mit dem gleichen
Themen-Namen, z.B.
Argumentübergabe
getopt(1): der Shell-Befehl
getopt(3): die C Funktion
getopt()
Usage Meldung
Manpages
Fehlerbehandlung
Wichtige man-page Kapitel
1
2
3
7
Kommandozeilenprogramme
Systemaufrufe (C Funktionen)
Bibliotheksaufrufe (C Funktionen)
Verschiedenes
Suchen in den manpages
man -k keyword bzw. apropos keyword
23
Entwicklung in C
Umgang mit Fehlern
D. Ratasich,
D. Prokesch
Programmerstellung
Übersetzen und
Linken
Makefiles
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
Fehlermeldungen auf stderr
Rückgabewert einer Funktion immer abfragen
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
Beim Auftreten eines Fehlers
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
Argumentbehandlung
Optionen/
Argumente
Argumentübergabe
getopt()
Usage Meldung
Manpages
Aussagekräftige Fehlermeldungen
Probleme in welchem Programm? (argv[0])
Welche Probleme? (z.B. “fopen failed”)
Ursache? (strerror(errno))
Terminieren des Programms
Freigeben von Ressourcen (z.B. temporäre Dateien)
exit(): Korrekter Exitcode als Argument
✓ EXIT_SUCCESS bei korrekter Beendigung
✗ 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
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Klassifizierung
Speicherregion: Statisch, Stack, Heap
Angeforderte Größe: konstant, dynamisch
Lebensdauer: Programm, Block, vom Programmierer
bestimmt
Bisher betrachtet
Statische Variablen (globale Definitionen)
Lokale Variablen fester Größe (lokale Definitionen)
Noch nicht betrachtet
Speicherplatz dynamischer Größe
Speicherplatz mit flexibler Lebensdauer
Zusammenfassung
29
Entwicklung in C
Globale Variablen
D. Ratasich,
D. Prokesch
Speicherverwaltung
Definition: Außerhalb von Funktionen oder static
Modifier
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
char hello[] = "hello";
void f(void)
{
static int keep;
...
}
Gültigkeitsdauer: Programm (Adresse stets gültig)
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Typischer Speicherbereich: Data oder BSS
Speicherplatzbedarf ist dem Übersetzer bekannt
Initialisiert (implizit oder explizit)
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
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Definition: In einem Anweisungsblock (C89: zu Beginn)
if (a > b) {
int x;
char c = ’A’;
...
}
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Gültigkeitsdauer: Bis zum Ende des Blocks
Freigabe des Speichers beim Verlassen des Blocks
Adresse verliert Gültigkeit
Typischer Speicherbereich: Stack
Speicherplatzbedarf ist dem Übersetzer bekannt
(Ausnahme: Arrays variabler Größe in C99)
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
Klassifizierung
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
Linux: ulimit -s
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
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Anfordern und Freigeben von Speicher zur Laufzeit
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
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Portable Bibliothek zur Speicherverwaltung –
A memory allocator
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
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
void *malloc(size_t size);
/* Beispiele
char *x
=
int *x
=
int *x_arr =
*/
malloc(sizeof (char));
malloc(sizeof *x);
malloc(sizeof (int) * n);
typedef struct { int x, y, r; } circle_t;
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
circle_t *circ1 = malloc(sizeof (circle_t));
circle_t *circ2 = malloc(sizeof *circ2);
Allokation von size Bytes zusammenhängenden
Speichers
Rückgabewert: Startadresse des Speicherbereichs
Adresse identifiziert Speicherbereich
Speicher ist nicht initialisiert (vgl. calloc(3))
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
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
void free(void *ptr);
Als Argument ptr wird entweder NULL oder eine gültige
Adresse erwartet.
Eine Adresse ist gültig wenn
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
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Ändert die Größe des durch ptr identifizierten
Speicherbereichs
Wird der Speicherbereich vergrößert, bleiben Daten
erhalten
Wird Speicherbereich verkleinert, bleiben die ersten size
Bytes erhalten
Erwartet gültige Adresse (wie free())
Daten können kopiert werden, Startadresse kann sich
ändern (Rückgabewert)
Falls Allokation fehlschlägt wird NULL zurückgegeben,
alter Speicherbereich bleibt gültig
Spezialfälle
ptr ist NULL → verhält sich wie malloc()
size ist 0 → verhält sich wie free()
43
Entwicklung in C
Beispiele: malloc()/free()
D. Ratasich,
D. Prokesch
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
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
Freigeben dynamisch allokierten Speichers
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
Freigeben dynamisch allokierten Speichers
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
Freigeben dynamisch allokierten Speichers
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
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Bildet Dateien oder flüchtigen Speicher im Adressraum
des aktuellen Prozesses ab
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
Anwendungen von mmap()
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
malloc Bibliotheksroutinen
Klassifizierung
Globale und
lokale
Variablen
Bibliothek (z.B. libc) verwaltet Speicherblöcke, die
wiederum vom Betriebssystem angefordert wurden
Online Algorithmus (keine Annahmen über zukünftiges
Allokationsverhalten)
Dynamisch
angeforderter
Speicher
Beispiele
Beispiel: Doug Lea’s malloc (dlmalloc)2
Weiterführendes
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)
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
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
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Programmierrichtlinien
Homogener, verständlicher Code
Vermeidung von fehleranfälligen Konstrukten
Erleichtern von automatischer Programmprüfung und
Debugging
Style Guides (z.B. BSD Kernel)
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
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Dynamische Überprüfung von Vorbedingungen,
Invarianten (z.B. in Schleifen) und Nachbedingungen
z.B. assert(ptr != NULL))
Stichwort: Design by Contract
Realisierung in C: assert(3)
Einbinden von <assert.h>
Deaktivieren durch gcc -DNDEBUG ...
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
Am Beispiel des Jet Propulsion Laboratory, Caltech3
Speicherverwaltung
Programmierstil
Maximal eine Bildschirmseite pro Funktion
eingeschränkte Verwendung des Präprozessors
Klassifizierung
Globale und
lokale
Variablen
Defensive Programmierung
Dynamisch
angeforderter
Speicher
großzügiges Verwenden von Zusicherungen
Variablensichtbarkeit minimieren
alle Rückgabewerte überprüfen
Berücksichtigen und Beheben aller Compilerwarnungen
Beispiele
Weiterführendes
Fehlerbehebung
Vereinfachen der Programmprüfung
Vermeidung
statisch begrenzte maximale Anzahl von
Schleifendurchläufen
einfache Kontrollstrukturen (kein goto, keine Rekursion)
keine dynamische Speicherallokation nach Initialisierung
eingeschränkte Verwendung von Zeigern
Programmanalyse
Debugging
Zusammenfassung
3
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
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Statische Analyse (Inspektion des Programmcodes)
Am Source Code oder Binärdatei
Einfache Form: Compilerwarnungen (-Wall, clang)
z.B. splint, BLAST, viele kommerzielle Tools
Dynamische Analyse (Prüfung während des
Programmablaufs)
Instrumentiertes Programm
z.B. dmalloc, valgrind
Debugging (Inspektion des laufenden Prozesses)
Debugnachrichten (printf)
Interaktiv, mit Hilfe eines Debuggers (z.B. gdb)
Zusammenfassung
56
Entwicklung in C
Statische Analysetools
D. Ratasich,
D. Prokesch
Analysieren Source Code des Programms
Speicherverwaltung
Erkennt viele typische Fehler (aber nicht alle)
Häufiges Problem: falsch Positive → Desensibilisierung
Klassifizierung
Globale und
lokale
Variablen
Fehlervorbeugung
Warnung bei fehleranfälligen Konstrukten
Strengere Typregeln
Dynamisch
angeforderter
Speicher
Beispiele
Fehlererkennung
Weiterführendes
Zugriff auf unintialisierten Speicher
Verwendung ungültiger Adressen
Verletzen von Zusicherungen
Fehlerbehebung
Vermeidung
Beispiel: splint4
Programmanalyse
Zusätzliche Annotationen: Erhöhen der Treffsicherheit,
stärkere Zusicherungen
Debugging
Zusammenfassung
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
Dynamische Analysen sammeln zusätzliche Informationen
während der Programmausführung
Klassifizierung
Globale und
lokale
Variablen
Qualität hängt daher von den Testläufen ab
Dynamisch
angeforderter
Speicher
Beispiel: valgrind5
Beispiele
Framework zur Instrumentierung von Programmen
Simuliert parallel zum Programm ein Modell zur
Fehlererkennung
memcheck: Hauptmodul um Fehler in der dynamischen
Speicherverwaltung zu finden
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
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
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Finden und Beheben der Ursache eines bekannten
Programmfehlers
Modifizieren und Testen des Programms
Zusätzliche Zusicherungen (assert(3))
Debugnachrichten
Mit Hilfe eines Debuggers
Anhalten und Inspektion des laufenden Prozesses
Inspektion des core dumps
Debugging
Zusammenfassung
63
Entwicklung in C
Debugnachrichten I
D. Ratasich,
D. Prokesch
Bedingt aktivieren mit Hilfe des Präprozessors:
Speicherverwaltung
gcc -g -DDEBUG ...
Klassifizierung
Deaktiviert: keine Performancebeinträchtigung
Globale und
lokale
Variablen
#ifdef DEBUG
Dynamisch
angeforderter
Speicher
Beispiele
#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
Erweiterte Ausgaben mit Hilfe von vordefinierten und
variadischen Makros6
Speicherverwaltung
Klassifizierung
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
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
Fehlerbehebung
Vermeidung
Inspektion eines laufenden Prozesses
Aufgaben des Debuggers
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
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
http://www.gnu.org/software/gdb
Debugging des Maschinencodes
Vorbereitung
Übersetzen mit -g (Debuggingsymbole)
Optimierungen verkomplizieren Debugging
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
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Programmstart im Debugger, z.B.:
gdb myprogram und mit run [args]
gdb -args myprogram [args] und mit run
Einen Core-Dump analysieren
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
An laufenden Prozess anhängen
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
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Programm bis zur nächsten Unterbrechung ausführen
Spezifizieren des Programms
file binary
Starten des Programms
run args...
Ausführen nach Unterbrechung continue
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
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
Punkte im Programm, an denen die Ausführung
unterbrochen werden soll
Realisierung in HW (CPU Unterstützung) oder SW
(Modifikation des Programmcodes)
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
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
Debugging
Zusammenfassung
70
Entwicklung in C
Watchpoints
D. Ratasich,
D. Prokesch
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Unterbricht Ausführung wenn sich Variable ändert
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
Anwendungsbereiche
Beobachten einer Variable über längeren Zeitraum
Falls unbekannt, wann sich Variable ändert
Catchpoints: Ausführung wird bei Auftreten bestimmter
Ereignisse unterbrochen
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
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Ausgabe des aktuellen Werts von C Expressions
print argc
print argv[0]
print/x &argc
p *((int*)0xbfffff2b0))
$1
$2
$3
$4
=
=
=
=
1
"hello"
0xbfffff2b0
42
Vermeidung
Ändern von Speicherwerten
set variable x=0
set (x=0)
Programmanalyse
Ausgabe bei jeder Unterbrechung mit display
Fehlerbehebung
Debugging
Zusammenfassung
72
Entwicklung in C
GDB und Signale
D. Ratasich,
D. Prokesch
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Als „Breakpoint“ konfigurierbar
SIGINT → Kontrolle an den Debugger
Signale können selektiv an Programm weitergegeben
werden
siehe info signals
z.B. handle SIGUSR1 nostop print pass
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Material zu GDB:
OSUE-Wiki:
http://wiki.vmars.tuwien.ac.at/index.php/Gdb
Tutorial:
http://beej.us/guide/bggdb/
Manual:
http://sourceware.org/gdb/onlinedocs/gdb/
73
Entwicklung in C
Zusammenfassung
D. Ratasich,
D. Prokesch
Speicherverwaltung
Klassifizierung
Globale und
lokale
Variablen
Dynamisch
angeforderter
Speicher
Beispiele
Weiterführendes
Fehlerbehebung
Vermeidung
Programmanalyse
Debugging
Zusammenfassung
Dynamische Speicherverwaltung
Speicherregionen und C
Dynamische Speicheranforderung mit malloc
Vermeidung von Fehlern
Programmierrichtlinien
Zusicherungen
Programmanalyse
statisch, wie z.B. mit splint
dynamisch, wie z.B. mit valgrind
Debugging
Debuggingnachrichten (C Präprozessor)
interaktiv, z.B. gdb
74
Document
Kategorie
Technik
Seitenansichten
4
Dateigröße
446 KB
Tags
1/--Seiten
melden