From: Lennart Poettering Date: Wed, 24 Aug 2022 08:41:23 +0000 (+0200) Subject: time-util: fix overflow condition in usec_sub_signed() X-Git-Tag: v252-rc1~351 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=782c6e5c9050ba2de141906732e0a7e14b0c1550;p=thirdparty%2Fsystemd.git time-util: fix overflow condition in usec_sub_signed() If the delta specified is INT64_MIN, and we negate that we'd end up at INT64_MAX+1 which is outside of the int64_t type. Hence let's treat this case specifically to avoid unintended overflows. --- diff --git a/src/basic/time-util.h b/src/basic/time-util.h index bf312442b0e..c98f95a5301 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -189,10 +189,15 @@ static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) { } static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) { + if (delta == INT64_MIN) { /* prevent overflow */ + assert_cc(-(INT64_MIN + 1) == INT64_MAX); + assert_cc(USEC_INFINITY > INT64_MAX); + return usec_add(timestamp, (usec_t) INT64_MAX + 1); + } if (delta < 0) return usec_add(timestamp, (usec_t) (-delta)); - else - return usec_sub_unsigned(timestamp, (usec_t) delta); + + return usec_sub_unsigned(timestamp, (usec_t) delta); } #if SIZEOF_TIME_T == 8 diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 58c5fa9be40..6b546fb9f57 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -311,10 +311,26 @@ TEST(usec_sub_signed) { assert_se(usec_sub_signed(4, 1) == 3); assert_se(usec_sub_signed(4, 4) == 0); assert_se(usec_sub_signed(4, 5) == 0); + assert_se(usec_sub_signed(USEC_INFINITY-3, -3) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY-3, -4) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY-3, -5) == USEC_INFINITY); assert_se(usec_sub_signed(USEC_INFINITY, 5) == USEC_INFINITY); + + assert_se(usec_sub_signed(0, INT64_MAX) == 0); + assert_se(usec_sub_signed(0, -INT64_MAX) == INT64_MAX); + assert_se(usec_sub_signed(0, INT64_MIN) == (usec_t) INT64_MAX + 1); + assert_se(usec_sub_signed(0, -(INT64_MIN+1)) == 0); + + assert_se(usec_sub_signed(USEC_INFINITY, INT64_MAX) == USEC_INFINITY); + assert_se(usec_sub_signed(USEC_INFINITY, -INT64_MAX) == USEC_INFINITY); + assert_se(usec_sub_signed(USEC_INFINITY, INT64_MIN) == USEC_INFINITY); + assert_se(usec_sub_signed(USEC_INFINITY, -(INT64_MIN+1)) == USEC_INFINITY); + + assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MAX) == USEC_INFINITY-1-INT64_MAX); + assert_se(usec_sub_signed(USEC_INFINITY-1, -INT64_MAX) == USEC_INFINITY); + assert_se(usec_sub_signed(USEC_INFINITY-1, INT64_MIN) == USEC_INFINITY); + assert_se(usec_sub_signed(USEC_INFINITY-1, -(INT64_MIN+1)) == USEC_INFINITY-1-((usec_t) (-(INT64_MIN+1)))); } TEST(format_timestamp) {