summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extmod/utime_mphal.c13
-rw-r--r--tests/extmod/ticks_add.py42
-rw-r--r--tests/extmod/ticks_add.py.exp36
3 files changed, 91 insertions, 0 deletions
diff --git a/extmod/utime_mphal.c b/extmod/utime_mphal.c
index 3d1cdfd82..cd91c9553 100644
--- a/extmod/utime_mphal.c
+++ b/extmod/utime_mphal.c
@@ -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);
diff --git a/tests/extmod/ticks_add.py b/tests/extmod/ticks_add.py
new file mode 100644
index 000000000..2f1ba6c81
--- /dev/null
+++ b/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")
diff --git a/tests/extmod/ticks_add.py.exp b/tests/extmod/ticks_add.py.exp
new file mode 100644
index 000000000..60dc6f5af
--- /dev/null
+++ b/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