C
-----------------
< Systemnaehe? C! >
-----------------
\
\ .~-~.
/^ ^\
(__ O O __)
\ \< >/ /
The good
- Standard seit 70er
- Portabel
- Low-Level
- Manual Memory Management
- Legacy Code
the bad
- Undefined Behaviour
- Keine Memory Safety Garantie
- Fehleranfaellige Parallelverarbeitung
- Error handling
- Dynamisches Linking
and the ugly
- Keine einheitliche Paketverwaltung
- Mehrere Build-Systeme
Undefined Behaviour
In C ist Undefined Behaviour (UB) nicht immer offensichtlich.
Anhand des unsafe
Keywords kann man in Rust sofort Codestellen erkennen, an
denen Undefined Behaviour auftreten kann.
Keine Scheu vor unsafe
!
C - Compiler Unterschiede
int main() { // 1
int i = 2; // 2 Initialize variable
int result = --i + i++; // 3
return 0; // 4
}
gcc: result=3 clang: result=2
C - Buffer Overflow
- Buffer mit bestimmter Groesse erstellen
- Daten in Buffer schreiben
- Daten sind groesser als Buffer
- Naheligender Speicher wird ueberschrieben -> Overflow
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
char *src = "This is a long string.";
memcpy(buffer, src, strlen(src));
printf("%s\n", buffer);
return 0;
}
C - Use after free
- Allokieren von Speicher
- Schreiben in den Speicher
- Freigeben des Speichers
- Lesen aus dem Speicher -> Fehlerhaft
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int)); // TODO check allocation success
*ptr = 42;
printf("ptr: %d\n", *ptr);
free(ptr);
// Pointer is dangling
printf("ptr after free: %d\n", *ptr);
return 0;
}
C - Double Free
- Speicher wird allokiert
- Pointer wird an free uebergeben
- Speicher is freigegeben, Pointer existiert weiter
- Pointer wird erneut an free uebergeben -> Welcher Speicher wird bereinigt?
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int *)malloc(sizeof(int));
free(ptr);
free(ptr);
return 0;
}
C - Invalid Index
- Index ist groesser als array
- Value enthaelt falsche Daten
#include <stdio.h>
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int value = arr[6];
printf("Value: %d\n", value);
return 0;
}
C - Divide by Zero
- Undefinded
- Manche Programme brechen ab, manche arbeiten mit falschem Ergebnis weiter
#include <stdio.h>
int main() {
int numerator = 10;
int denominator = 0;
int result = numerator / denominator;
printf("Result: %d\n", result);
return 0;
}
C - Dangling Pointer
- Value in einem lokalen Scope
- Dereferenzieren des Values im lokalen Scope
- Referenz (Pointer) wird returned
- Value existiert nicht mehr, Pointer schon
- Pointer zeig auf fehlerhaften Speicher
int *getDanglingPointer() {
int value = 42;
return &value;
}
int main() {
int *ptr = getDanglingPointer();
*ptr = 10; // Unsicher welcher Speicher beschrieben wird
printf("%d", *ptr);
return 0;
}