aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Green <aarongreen@google.com>2024-01-25 21:50:28 +0000
committerCQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>2024-01-25 21:50:28 +0000
commit883b7fb0ccf1187bcb88851b00a327fb0c240af8 (patch)
tree46c0ce7d0bb1d1164cead45ac99bc13e13f19333
parent44f2e8f6671c4c46fd35140ad0b4a3a4fa4d4d79 (diff)
downloadpigweed-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.h8
-rw-r--r--pw_assert/public/pw_assert/internal/check_impl.h10
-rw-r--r--pw_preprocessor/docs.rst33
-rw-r--r--pw_preprocessor/public/pw_preprocessor/compiler.h25
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)