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;
}