Skip to content

Undefined behavior on timer rollover #3

@edgar-bonet

Description

@edgar-bonet

The method FilterOnePole::input(float) starts with these statements:

long time = micros();
ElapsedUS = float(time - LastUS);   // cast to float here, for math

When micros() reaches 231, which happens roughly 35.8 minutes after the program starts, time becomes a large negative number, and the subtraction time - LastUS overflows.

In C and C++, arithmetic overflow of signed integral types is undefined behavior. This means the program is incorrect, and anything can happen, including (but not limited to) the subtraction giving the expected result. Just for illustration, here is a recent example of the kind of surprises you can get with integer overflows.

The same bug is present in FilterTwoPole.cpp and in FilterDerivative.cpp.

The fix is very simple: all variables holding timestamps (LastUS, LastTimeUS, thisUS, time and now) should be declared unsigned long. This is the type returned by micros(), and it is not a coincidence that it is the right type for timing calculations. Unlike signed integers, the arithmetics on unsigned integers are specified by the C and C++ standards to be done modulo MAX(type)+1. This guarantees that the subtraction will yield the correct result even across a micros() rollover.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions