Skip to content

Commit

Permalink
extmod/utime_mphal: Make ticks_add check for overflow of delta.
Browse files Browse the repository at this point in the history
Work done in collaboration with @jimmo.

Signed-off-by: Damien George <damien@micropython.org>
  • Loading branch information
dpgeorge committed Oct 14, 2022
1 parent 89b3207 commit 815920c
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
13 changes: 13 additions & 0 deletions extmod/utime_mphal.c
Expand Up @@ -95,6 +95,19 @@ STATIC mp_obj_t time_ticks_add(mp_obj_t ticks_in, mp_obj_t delta_in) {
// we assume that first argument come from ticks_xx so is small int
mp_uint_t ticks = MP_OBJ_SMALL_INT_VALUE(ticks_in);
mp_uint_t delta = mp_obj_get_int(delta_in);

// Check that delta does not overflow the range that ticks_diff can handle.
// This ensures the following:
// - ticks_diff(ticks_add(T, delta), T) == delta
// - ticks_diff(T, ticks_add(T, delta)) == -delta
// The latter requires excluding delta=-TICKS_PERIOD/2.
//
// This unsigned comparison is equivalent to a signed comparison of:
// delta <= TICKS_PERIOD/2 || delta >= TICKS_PERIOD/2
if (delta + MICROPY_PY_UTIME_TICKS_PERIOD / 2 - 1 >= MICROPY_PY_UTIME_TICKS_PERIOD - 1) {
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ticks interval overflow"));
}

return MP_OBJ_NEW_SMALL_INT((ticks + delta) & (MICROPY_PY_UTIME_TICKS_PERIOD - 1));
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_utime_ticks_add_obj, time_ticks_add);
Expand Down
42 changes: 42 additions & 0 deletions tests/extmod/ticks_add.py
@@ -0,0 +1,42 @@
try:
from utime import ticks_diff, ticks_add
except ImportError:
print("SKIP")
raise SystemExit

# Maximum value returned from ticks_add, ticks_ms, etc.
TICKS_MAX = ticks_add(0, -1)
# Maximum value returned from ticks_diff.
TICKS_INTERVAL_MAX = TICKS_MAX // 2

# Invariants:
# - ticks_diff(ticks_add(T, delta), T) == delta
# - ticks_diff(T, ticks_add(T, delta)) == -delta

# Check actual values of ticks_add.
print(ticks_add(20, 12))
print(ticks_add(20, -12))

# Check invariant.
print(ticks_diff(ticks_add(100, 123), 100))
print(ticks_diff(ticks_add(100, -123), 100))
print(ticks_diff(100, ticks_add(100, 123)))
print(ticks_diff(100, ticks_add(100, -123)))

# Check limits.
for T in (0, 10, TICKS_MAX):
for delta in (
-TICKS_INTERVAL_MAX - 1,
-TICKS_INTERVAL_MAX,
0,
TICKS_INTERVAL_MAX,
TICKS_INTERVAL_MAX + 1,
):
try:
print(ticks_diff(ticks_add(T, delta), T) == delta)
except OverflowError:
print("OverflowError")
try:
print(ticks_diff(T, ticks_add(T, delta)) == -delta)
except OverflowError:
print("OverflowError")
36 changes: 36 additions & 0 deletions tests/extmod/ticks_add.py.exp
@@ -0,0 +1,36 @@
32
8
123
-123
-123
123
OverflowError
OverflowError
True
True
True
True
True
True
OverflowError
OverflowError
OverflowError
OverflowError
True
True
True
True
True
True
OverflowError
OverflowError
OverflowError
OverflowError
True
True
True
True
True
True
OverflowError
OverflowError

0 comments on commit 815920c

Please sign in to comment.