diff --git a/src/basic/macro.h b/src/basic/macro.h index 3bf982803d..e6f89608f4 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -457,8 +457,15 @@ static inline int __coverity_check_and_return__(int condition) { _copy; \ }) +#define saturate_add(x, y, limit) \ + ({ \ + typeof(limit) _x = (x); \ + typeof(limit) _y = (y); \ + _x > (limit) || _y >= (limit) - _x ? (limit) : _x + _y; \ + }) + static inline size_t size_add(size_t x, size_t y) { - return y >= SIZE_MAX - x ? SIZE_MAX : x + y; + return saturate_add(x, y, SIZE_MAX); } typedef struct { diff --git a/src/test/test-macro.c b/src/test/test-macro.c index ba319953cd..c39f64b385 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -6,6 +6,15 @@ #include "macro.h" #include "tests.h" +TEST(saturate_add) { + assert_se(saturate_add(1, 2, UINT8_MAX) == 3); + assert_se(saturate_add(1, UINT8_MAX-2, UINT8_MAX) == UINT8_MAX-1); + assert_se(saturate_add(1, UINT8_MAX-1, UINT8_MAX) == UINT8_MAX); + assert_se(saturate_add(1, UINT8_MAX, UINT8_MAX) == UINT8_MAX); + assert_se(saturate_add(2, UINT8_MAX, UINT8_MAX) == UINT8_MAX); + assert_se(saturate_add(60, 60, 50) == 50); +} + TEST(align_power2) { unsigned long i, p2;