Skip to content
📖 Auto vs Modern CBook contents

Chapter 15: Program Failure ​

Level 2 — Cognition

Undefined behavior, error codes, signals -- how things go wrong in C and how Auto prevents them.

Programs fail. The question is not whether failure will occur, but how the language helps you prevent, detect, and recover from it. C's approach to failure is minimal: the language assumes the programmer is always right and provides few safety nets. Auto takes the opposite approach -- the language helps the programmer avoid failure through compile-time checks and runtime safety.


15.1 Wrongdoings ​

C classifies program misbehavior into several categories. The most dangerous is undefined behavior (UB):

Undefined behavior: behavior for which the standard imposes no requirements.

UB means the compiler is allowed to do literally anything. Common examples:

c
// C Deep Dive: undefined behavior
int arr[5];
arr[10] = 42;           // UB: out-of-bounds access

int *p = NULL;
*p = 42;                // UB: null pointer dereference

int x;
printf("%d\n", x);      // UB: reading uninitialized variable

int a = INT_MAX;
int b = a + 1;          // UB: signed integer overflow

free(p);
*p = 42;                // UB: use after free

What actually happens with UB in practice:

ScenarioPossible consequence
Buffer overflowSilent data corruption
Null dereferenceSegmentation fault (crash)
Use after freeArbitrary code execution
Integer overflowIncorrect results
Type confusionData corruption, security hole

Compilers exploit UB for optimization. If the standard says the behavior is undefined, the compiler may assume it never happens:

c
// C Deep Dive: compiler exploits UB
int *check(int *p) {
    int x = *p;        // dereference p
    if (p == NULL) {   // compiler removes this: if p were NULL,
        return NULL;   // the dereference above would be UB,
    }                   // and UB "doesn't happen"
    return p;
}

How Auto prevents UB. Auto eliminates entire categories of UB through:

  • Bounds checking: array accesses are validated at compile time where possible, runtime where necessary.
  • Null safety: there are no null pointers in Auto. Optional values use explicit Option types.
  • Initialization enforcement: every variable must be initialized.
  • No pointer arithmetic: array indexing replaces all pointer arithmetic.
  • Overflow detection: integer overflow is caught at runtime.
auto
// Auto: UB prevention
fn safe_divide(a int, b int) int {
    if b == 0 {
        print("Error: division by zero")
        return 0
    }
    a / b
}

fn safe_access(arr [5]int, index int) int {
    if index < 0 || index >= 5 {
        print("Error: index out of bounds")
        return 0
    }
    arr[index]
}

Released under the MIT License.