Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 655 of 9369. Embedded Systems Reliability and SafetyFree lesson

Implementing Defensive Input Validation

You will develop robust input sanitization routines to ensure all external data conforms to expected bounds and integrity constraints.

In this lesson, you will learn how to design robust input sanitization routines that treat all external data as untrusted, ensuring system stability even when hardware interfaces or sensors behave unexpectedly.

In embedded systems, we often assume that data arriving from an ADC, a serial bus, or a user interface will fall within a "sane" range. However, hardware components can fail, electromagnetic interference can corrupt packets, and peripheral registers can return garbage values. If your firmware blindly trusts these values, you risk buffer overflows, division-by-zero errors, or logic state machine corruption.

The Principle of Fail-Safe Validation

Defensive validation requires three steps: Range Checking, Type/Format Verification, and Deterministic Handling. Never rely on the peripheral to provide valid data; always wrap incoming data in a validation gate before it propagates into your business logic.

Consider this sensor reading example:

#define SENSOR_MIN_MV 500
#define SENSOR_MAX_MV 4500

uint16_t get_validated_sensor_value(uint16_t raw_input) {
    // 1. Boundary Check
    if (raw_input < SENSOR_MIN_MV || raw_input > SENSOR_MAX_MV) {
        // 2. Error Recovery / Safety State
        log_hardware_fault(raw_input);
        return SENSOR_DEFAULT_SAFE_VAL;
    }
    
    return raw_input;
}

Why Sanitization Matters

By centralizing validation, you decouple your processing logic from hardware unpredictability. If the raw_input fails the bounds check, the system doesn't crash; it triggers an error-handling path that might involve resetting the sensor or putting the system into a safe state (e.g., stopping a motor).

When implementing these routines, ensure your validation logic is constant-time and free of branches that could create timing side-channels, keeping it consistent with the deterministic design principles we’ve discussed. Remember, if your logic relies on a variable that originated outside the CPU's local memory—whether from a memory-mapped register or a communication peripheral—it must pass a validation routine before being used as an index, a divisor, or a loop counter.

Key Takeaway: Never trust input data at the boundary; implement explicit range and sanity checks to ensure that unexpected hardware signals cannot propagate into valid system logic.