Skip to content

Undefined behavior on timer rollover #3

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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