diff options
author | Aaron Green <aarongreen@google.com> | 2024-01-25 21:50:28 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2024-01-25 21:50:28 +0000 |
commit | 883b7fb0ccf1187bcb88851b00a327fb0c240af8 (patch) | |
tree | 46c0ce7d0bb1d1164cead45ac99bc13e13f19333 | |
parent | 44f2e8f6671c4c46fd35140ad0b4a3a4fa4d4d79 (diff) | |
download | pigweed-883b7fb0ccf1187bcb88851b00a327fb0c240af8.tar.gz |
pw_preprocessor: Add integer-overflow macros
This CL adds:
* PW_ADD_OVERFLOW, which wraps __builtin_add_overflow,
* PW_SUB_OVERFLOW, which wraps __builtin_sub_overflow, and
* PW_MUL_OVERFLOW, which wraps __builtin_mul_overflow.
It also adds checks in pw_assert to make use of these macros.
Change-Id: I1c74711412b2602bf5af94c5d88fb35232d6da0b
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/187653
Commit-Queue: Aaron Green <aarongreen@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
-rw-r--r-- | pw_assert/public/pw_assert/check.h | 8 | ||||
-rw-r--r-- | pw_assert/public/pw_assert/internal/check_impl.h | 10 | ||||
-rw-r--r-- | pw_preprocessor/docs.rst | 33 | ||||
-rw-r--r-- | pw_preprocessor/public/pw_preprocessor/compiler.h | 25 |
4 files changed, 76 insertions, 0 deletions
diff --git a/pw_assert/public/pw_assert/check.h b/pw_assert/public/pw_assert/check.h index 57b443790..dbe54595a 100644 --- a/pw_assert/public/pw_assert/check.h +++ b/pw_assert/public/pw_assert/check.h @@ -76,6 +76,14 @@ // PW_CHECK_FLOAT_EXACT_EQ(a, b, msg, ...) Asserts a == b // PW_CHECK_FLOAT_EXACT_NE(a, b, msg, ...) Asserts a != b // +// Integer-overflow asserts for integer types: +// PW_CHECK_ADD(a, b, out, msg, ...) +// Asserts a + b does not overflow and stores the result in out. +// PW_CHECK_SUB(a, b, out, msg, ...) +// Asserts a - b does not overflow and stores the result in out. +// PW_CHECK_MUL(a, b, out, msg, ...) +// Asserts a * b does not overflow and stores the result in out. +// // The above CHECK_*_*() are also available in DCHECK variants, which will // only evaluate their arguments and trigger if the NDEBUG macro is defined. // diff --git a/pw_assert/public/pw_assert/internal/check_impl.h b/pw_assert/public/pw_assert/internal/check_impl.h index 3755f75dd..3bf808017 100644 --- a/pw_assert/public/pw_assert/internal/check_impl.h +++ b/pw_assert/public/pw_assert/internal/check_impl.h @@ -130,6 +130,16 @@ #define PW_DCHECK_FLOAT_EXACT_EQ(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_EQ(__VA_ARGS__) #define PW_DCHECK_FLOAT_EXACT_NE(...) if (!(PW_ASSERT_ENABLE_DEBUG)) {} else PW_CHECK_FLOAT_EXACT_NE(__VA_ARGS__) +// Debug checks for integer overflows: ADD, SUB, MUL. +#define PW_CHECK_ADD(a, b, out, ...) PW_CHECK(!PW_ADD_OVERFLOW(a, b, out), __VA_ARGS__) +#define PW_CHECK_SUB(a, b, out, ...) PW_CHECK(!PW_SUB_OVERFLOW(a, b, out), __VA_ARGS__) +#define PW_CHECK_MUL(a, b, out, ...) PW_CHECK(!PW_MUL_OVERFLOW(a, b, out), __VA_ARGS__) + +// Debug checks for integer overflows: ADD, SUB, MUL. +#define PW_DCHECK_ADD(a, b, out, ...) PW_DCHECK(!PW_ADD_OVERFLOW(a, b, out), __VA_ARGS__) +#define PW_DCHECK_SUB(a, b, out, ...) PW_DCHECK(!PW_SUB_OVERFLOW(a, b, out), __VA_ARGS__) +#define PW_DCHECK_MUL(a, b, out, ...) PW_DCHECK(!PW_MUL_OVERFLOW(a, b, out), __VA_ARGS__) + // clang-format on // PW_CHECK_OK - If condition does not evaluate to PW_STATUS_OK, crash. Message diff --git a/pw_preprocessor/docs.rst b/pw_preprocessor/docs.rst index 15e9104e4..cb8d018b9 100644 --- a/pw_preprocessor/docs.rst +++ b/pw_preprocessor/docs.rst @@ -264,6 +264,39 @@ a single line if necessary. Whenever possible, fix the underlying issues about which the compiler is warning, rather than silencing the diagnostics. +Integer with Overflow Checking +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``pw_preprocessor/compiler.h`` provides macros for performing arithmetic +operations and checking whether it overflowed. + +.. c:macro:: PW_ADD_OVERFLOW(a, b, out) + + PW_ADD_OVERFLOW adds two integers while checking for overflow. + + Returns true if the result of `a + b` overflows the type of `out`; otherwise + stores the result in `out` and returns false. + + See also `PW_CHECK_ADD`. + +.. c:macro:: PW_SUB_OVERFLOW(a, b, out) + + PW_SUB_OVERFLOW subtracts an integer from another while checking for + overflow. + + Returns true if the result of `a - b` overflows the type of `out`; otherwise + stores the result in `out` and returns false. + + See also `PW_CHECK_SUB`. + +.. c:macro:: PW_MUL_OVERFLOW(a, b, out) + + PW_MUL_OVERFLOW multiplies two integers while checking for overflow. + + Returns true if the result of `a * b` overflows the type of `out`; otherwise + stores the result in `out` and returns false. + + See also `PW_CHECK_MUL`. + pw_preprocessor/concat.h ------------------------ Defines the ``PW_CONCAT(...)`` macro, which expands its arguments if they are diff --git a/pw_preprocessor/public/pw_preprocessor/compiler.h b/pw_preprocessor/public/pw_preprocessor/compiler.h index 8bcc0d644..f6564a33e 100644 --- a/pw_preprocessor/public/pw_preprocessor/compiler.h +++ b/pw_preprocessor/public/pw_preprocessor/compiler.h @@ -216,3 +216,28 @@ #else #define PW_ATTRIBUTE_LIFETIME_BOUND #endif // PW_ATTRIBUTE_LIFETIME_BOUND + +/// PW_ADD_OVERFLOW adds two integers while checking for overflow. +/// +/// Returns true if the result of `a + b` overflows the type of `out`; otherwise +/// stores the result in `out` and returns false. +/// +/// See also `PW_CHECK_ADD`. +#define PW_ADD_OVERFLOW(a, b, out) __builtin_add_overflow(a, b, out) + +/// PW_SUB_OVERFLOW subtracts an integer from another while checking for +/// overflow. +/// +/// Returns true if the result of `a - b` overflows the type of `out`; otherwise +/// stores the result in `out` and returns false. +/// +/// See also `PW_CHECK_SUB`. +#define PW_SUB_OVERFLOW(a, b, out) __builtin_sub_overflow(a, b, out) + +/// PW_MUL_OVERFLOW multiplies two integers while checking for overflow. +/// +/// Returns true if the result of `a * b` overflows the type of `out`; otherwise +/// stores the result in `out` and returns false. +/// +/// See also `PW_CHECK_MUL`. +#define PW_MUL_OVERFLOW(a, b, out) __builtin_mul_overflow(a, b, out) |