liveBook · Manning

Chapter 15: Program failure

What you will learn in chapter 15 of Modern C, Third Edition

The introduction frames program failure around its causes, sketches three ways failures arise, and limits the chapter’s scope to failures that manifest during execution.

After this chapter you will be able to

What it builds on

Section by section

Introduction

The introduction frames program failure around its causes, sketches three ways failures arise, and limits the chapter’s scope to failures that manifest during execution.

Key terms: undefined behavior, program failure, wrongdoings, program state degradation, unfortunate incidents, program execution, compile time, compilation, linkage, startup failures

15.1 Wrongdoings

Introduces wrongdoings as actions, events, or omissions that directly cause program failure, using a car accident to distinguish plausible causes from things merely present.

Key terms: wrongdoings, program failures

15.1.1 Arithmetic violations

This section explains when arithmetic on numbers and pointers is invalid, and why floating-point behavior depends on the platform.

Key terms: exceptional condition, division by zero, modulo by zero, INT_MIN, bit-shift, floating-point environment, INFINITY, <fenv.h>, FE_DIVBYZERO, fetestexcept

15.1.2 Invalid conversions

This section identifies conversions that can fail or produce nonportable results and distinguishes a valid conversion from permission to use its result.

Key terms: unsigned type, modulus, implementation defined, precision, pointer, uintptr_t, aligned, conversion, pointer-to-pointer conversion, accessed

15.1.3 Value violations

This subsection explains how wrong values can cause C library calls to fail and why detecting such violations usually requires checking the functions’ specifications.

Key terms: invalid values, call arguments, not representable, static analyzer tools, specifications

15.1.4 Type violations

This section explains how accessing objects or calling functions through the wrong type can cause failure, and why avoiding unnecessary pointer conversions and mismatched function prototypes helps prevent it.

Key terms: type violations, pointers, different type, prototype, function pointer, translation units

15.1.5 Access violations

This section identifies common access violations in C and explains why code using pointers and arrays must guard against them.

Key terms: access violations, pointers, arrays, null pointer dereference

15.1.6 Value misinterpretation

This section explains how accessing an object whose bits have no valid interpretation for its type can cause a value misinterpretation, and why representation bytes should not be changed directly.

Key terms: value misinterpretation, indeterminate representation, uninitialized, malloc, calloc, non-value representation, bool, representation bytes

15.1.7 Explicit invalidation

This section explains what C23’s unreachable() asserts, when that assertion is justified, and why other failures cannot stand in for it.

Key terms: unreachable(), array parameters with bounds, null pointers, undefined state, exit, abort, unreachable, wrongdoing

15.2 Program state degradation

The section explains why program state degradation is harder to address than an individual wrongdoing.

Key terms: program state degradation, wrongdoings, interplay of several actions

15.2.1 Unbounded recursion

This subsection explains how recursion without reliable progress or a well-defined stopping condition can exhaust function-call resources and crash a program.

Key terms: program state degradation, recursion, progress, bottom of the recursion, resources for function calls

15.2.2 Storage exhaustion

This section explains how stack and heap storage can be exhausted, and why heap allocation failure is easier to detect.

Key terms: function call contexts, stack, stack overflow, unbounded recursion, variable-length arrays, VLAs, variably modified (VM) types, heap, null pointer, storage exhaustion

15.2.3 Other scarce resources

The section explains that runtime resources beyond storage can be exhausted, how their use accumulates, and whether exhaustion can be detected.

Key terms: scarce resources, release, fopen, stream, file, failure mode, va_start, va_copy

15.3 Unfortunate incidents

This section explains unfortunate incidents as rare failures caused by distant events aligning, using a traffic collision to show why they are hard to anticipate.

Key terms: unfortunate incidents, wrongdoings, resource exhaustion, collisions

15.3.1 Escalating state degradation

Continuing execution after resource exhaustion can turn degraded program state into an incident with wider consequences.

Key terms: state degradation, stack or heap exhaustion, unfortunate incidents

15.3.2 Collisions and race conditions

This section explains how unsequenced access to the same object can cause failures, including less obvious cases involving pointers, signal handlers, and threads.

Key terms: sequencing, unsequenced access, side effects, p == q, *p, *q, unsequenced accesses, race conditions, signal handler, threads of execution

15.3.3 Inappropriate library calls and macro invocations

This section shows how calling a C library function or invoking a macro outside its permitted context can jeopardize execution or portability.

Key terms: signal, multithreaded program, setjmp macro, portability, C standard

15.3.4 Deadlocks

This section explains deadlock as a cyclic resource dependency, illustrates it with a congested roundabout, and locates deadlocks in multithreaded C programs.

Key terms: deadlock failure, cyclic chain of dependencies, resource conflicts, multithreaded context, deadlocks

15.4 Series of unfortunate events

This section explains how executions can fail by continuing without observable progress, using loops, recursion, and threaded livelocks as examples.

Key terms: finite set of states, observable side effects, progress, obscure, visible side effect, [[unsequenced]], INT_MAX, livelock, deadlock, detours

15.5 Dealing with failures

The section distinguishes how to avoid wrongdoings, detect resource-related degradation, and limit or prevent harder-to-detect unfortunate incidents.

Key terms: preconditions, wrongdoings, program state degeneration, error returns, errno, unfortunate incidents, signals, trap, termination functions, Byzantine failure

15.6 Error checking and cleanup

The section shows how to detect and report errors while preserving state and freeing allocated memory, including when cleanup requires a goto.

Key terms: preconditions, error conditions, negative constant values, error macros, errno, global state, error_cleanup, malloc, realloc, free

15.7 Summary

Where this is used later

Concepts explained in this chapter

← Chapter 14: More involved processing and I/O Chapter 16: Performance →

These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.