On Tue, Nov 18, 2025 at 11:39 AM Gaetan Rivet via dev < [email protected]> wrote:
> Add helpers to do simple arithmetic operations safely on u64 integers. > Additional, substraction and multiplication overflow are detected and > avoided. > > Signed-off-by: Gaetan Rivet <[email protected]> > --- > lib/util.h | 25 ++++++++++++++++++ > tests/library.at | 5 ++++ > tests/test-util.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 95 insertions(+) > > diff --git a/lib/util.h b/lib/util.h > index ef993626a1..18dfd6975a 100644 > --- a/lib/util.h > +++ b/lib/util.h > @@ -590,6 +590,31 @@ ovs_u128_is_superset(ovs_u128 super, ovs_u128 sub) > uint_is_superset(super.u64.lo, sub.u64.lo)); > } > > +static inline uint64_t > +ovs_u64_safeadd(uint64_t a, uint64_t b) > +{ > + return (UINT64_MAX - a < b) ? UINT64_MAX : a + b; > +} > + > +static inline uint64_t > +ovs_u64_safesub(uint64_t a, uint64_t b) > +{ > + return (a < b) ? 0 : a - b; > +} > + > +static inline uint64_t > +ovs_u64_safemul(uint64_t a, uint64_t b) > +{ > + static const uint64_t sqrt_u64_max = UINT64_C(1) << (64 / 2); > + > + if ((a >= sqrt_u64_max || b >= sqrt_u64_max) && > + a > 0 && UINT64_MAX / a < b) { > + return UINT64_MAX; > + } else { > + return a * b; > + } > +} > Minor point but why not just use: bool __builtin_add_overflow (type1 x, type2 y, type3 *sum); bool __builtin_sub_overflow (type1 x, type2 y, type3 *diff); bool __builtin_mul_overflow (type1 x, type2 y, type3 *prod); -M > + > void xsleep(unsigned int seconds); > void xnanosleep(uint64_t nanoseconds); > void xnanosleep_no_quiesce(uint64_t nanoseconds); > diff --git a/tests/library.at b/tests/library.at > index 20899bde00..507d343d11 100644 > --- a/tests/library.at > +++ b/tests/library.at > @@ -254,6 +254,11 @@ AT_KEYWORDS([sat math sat_math]) > AT_CHECK([ovstest test-util sat_math]) > AT_CLEANUP > > +AT_SETUP([safe U64 operations]) > +AT_KEYWORDS([math]) > +AT_CHECK([ovstest test-util safe-u64]) > +AT_CLEANUP > + > AT_SETUP([snprintf]) > AT_CHECK([ovstest test-util snprintf]) > AT_CLEANUP > diff --git a/tests/test-util.c b/tests/test-util.c > index 5d88d38f26..2650c9507e 100644 > --- a/tests/test-util.c > +++ b/tests/test-util.c > @@ -1183,6 +1183,70 @@ test_sat_math(struct ovs_cmdl_context *ctx > OVS_UNUSED) > } > } > > +static void > +test_safe_u64(struct ovs_cmdl_context *ctx OVS_UNUSED) > +{ > + struct { > + uint64_t a, b, expected; > + } add_cases[] = { > + { 0, 0, 0, }, > + { 1, 2, 3, }, > + { 0, UINT64_MAX, UINT64_MAX, }, > + { UINT64_MAX, 0, UINT64_MAX, }, > + { -1, 0, UINT64_MAX, }, > + { -1, -1, UINT64_MAX, }, > + { UINT64_MAX / 2, UINT64_MAX / 2, UINT64_MAX - 1, }, > + { 2, UINT64_MAX / 2, UINT64_MAX / 2 + 2, }, > + }, > + sub_cases[] = { > + { 0, 0, 0, }, > + { 1, 2, 0, }, > + { 0, UINT64_MAX, 0, }, > + { UINT64_MAX, 0, UINT64_MAX, }, > + { -1, 0, UINT64_MAX, }, > + { -1, -1, 0, }, > + { UINT64_MAX / 2, UINT64_MAX / 2, 0, }, > + { 2, UINT64_MAX / 2, 0, }, > + }, > + mul_cases[] = { > + { 0, 0, 0, }, > + { 0, 2, 0, }, > + { 1, 2, 2, }, > + { 0, UINT64_MAX, 0, }, > + { UINT64_MAX, 0, 0, }, > + { -1, 0, 0, }, > + { 0, -1, 0, }, > + { -1, -1, UINT64_MAX, }, > + { 4294967296, 4294967296, UINT64_MAX, }, > + { UINT64_MAX / 2, UINT64_MAX / 2, UINT64_MAX, }, > + { 2, UINT64_MAX / 2, UINT64_MAX - 1, }, > + }; > + > + for (size_t i = 0; i < ARRAY_SIZE(add_cases); i++) { > + uint64_t a = add_cases[i].a; > + uint64_t b = add_cases[i].b; > + uint64_t expected = add_cases[i].expected; > + > + ovs_assert(ovs_u64_safeadd(a, b) == expected); > + } > + > + for (size_t i = 0; i < ARRAY_SIZE(sub_cases); i++) { > + uint64_t a = sub_cases[i].a; > + uint64_t b = sub_cases[i].b; > + uint64_t expected = sub_cases[i].expected; > + > + ovs_assert(ovs_u64_safesub(a, b) == expected); > + } > + > + for (size_t i = 0; i < ARRAY_SIZE(mul_cases); i++) { > + uint64_t a = mul_cases[i].a; > + uint64_t b = mul_cases[i].b; > + uint64_t expected = mul_cases[i].expected; > + > + ovs_assert(ovs_u64_safemul(a, b) == expected); > + } > +} > + > #ifndef _WIN32 > static void > test_file_name(struct ovs_cmdl_context *ctx) > @@ -1220,6 +1284,7 @@ static const struct ovs_cmdl_command commands[] = { > {"ovs_scan", NULL, 0, 0, test_ovs_scan, OVS_RO}, > {"snprintf", NULL, 0, 0, test_snprintf, OVS_RO}, > {"sat_math", NULL, 0, 0, test_sat_math, OVS_RO}, > + {"safe-u64", NULL, 0, 0, test_safe_u64, OVS_RO}, > #ifndef _WIN32 > {"file_name", NULL, 1, INT_MAX, test_file_name, OVS_RO}, > #endif > -- > 2.34.1 > > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
