]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add <isc/overflow.h> for checked mul, add, and sub
authorTony Finch <fanf@isc.org>
Tue, 6 Jun 2023 14:11:13 +0000 (15:11 +0100)
committerOndřej Surý <ondrej@isc.org>
Tue, 27 Jun 2023 10:38:09 +0000 (12:38 +0200)
The `ISC_OVERFLOW_XXX()` macros are usually wrappers around
`__builtin_xxx_overflow()`, with alternative implementations
for compilers that lack the builtins.

Replace the overflow checks in `isc/time.c` with the new macros.

lib/isc/Makefile.am
lib/isc/include/isc/overflow.h [new file with mode: 0644]
lib/isc/time.c

index 4f8880dfb8724d275fc264e513cd4387d2f2712f..df2d327213ea6cf308e34d3a6c6b88d667da593b 100644 (file)
@@ -61,6 +61,7 @@ libisc_la_HEADERS =                   \
        include/isc/nonce.h             \
        include/isc/once.h              \
        include/isc/os.h                \
+       include/isc/overflow.h          \
        include/isc/parseint.h          \
        include/isc/pause.h             \
        include/isc/portset.h           \
diff --git a/lib/isc/include/isc/overflow.h b/lib/isc/include/isc/overflow.h
new file mode 100644 (file)
index 0000000..c272cfa
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#pragma once
+
+#include <isc/util.h>
+
+/*
+ * It is awkward to support signed numbers as well, so keep it simple
+ * (with a safety check).
+ */
+#define ISC_OVERFLOW_IS_UNSIGNED(a)                                      \
+       ({                                                               \
+               STATIC_ASSERT((typeof(a))-1 > 0,                         \
+                             "overflow checks require unsigned types"); \
+               (a);                                                     \
+       })
+
+#define ISC_OVERFLOW_UINT_MAX(a) ISC_OVERFLOW_IS_UNSIGNED((typeof(a))-1)
+
+#define ISC_OVERFLOW_UINT_MIN(a) ISC_OVERFLOW_IS_UNSIGNED(0)
+
+/*
+ * Return true on overflow, e.g.
+ *
+ *     bool overflow = ISC_OVERFLOW_MUL(count, sizeof(array[0]), &bytes);
+ *     INSIST(!overflow);
+ */
+
+#if HAVE_BUILTIN_MUL_OVERFLOW
+#define ISC_OVERFLOW_MUL(a, b, cp) __builtin_mul_overflow(a, b, cp)
+#else
+#define ISC_OVERFLOW_MUL(a, b, cp)                                           \
+       ((ISC_OVERFLOW_UINT_MAX(a) / (b) > (a)) ? (*(cp) = (a) * (b), false) \
+                                               : true)
+#endif
+
+#if HAVE_BUILTIN_ADD_OVERFLOW
+#define ISC_OVERFLOW_ADD(a, b, cp) __builtin_add_overflow(a, b, cp)
+#else
+#define ISC_OVERFLOW_ADD(a, b, cp)                                           \
+       ((ISC_OVERFLOW_UINT_MAX(a) - (b) > (a)) ? (*(cp) = (a) + (b), false) \
+                                               : true)
+#endif
+
+#if HAVE_BUILTIN_SUB_OVERFLOW
+#define ISC_OVERFLOW_SUB(a, b, cp) __builtin_sub_overflow(a, b, cp)
+#else
+#define ISC_OVERFLOW_SUB(a, b, cp)                                           \
+       ((ISC_OVERFLOW_UINT_MIN(a) + (b) < (a)) ? (*(cp) = (a) - (b), false) \
+                                               : true)
+#endif
+
+#define ISC_CHECKED_MUL(a, b)                                      \
+       ({                                                         \
+               typeof(a) _c;                                      \
+               bool      _overflow = ISC_OVERFLOW_MUL(a, b, &_c); \
+               INSIST(!_overflow);                                \
+               _c;                                                \
+       })
+
+#define ISC_CHECKED_ADD(a, b)                                      \
+       ({                                                         \
+               typeof(a) _c;                                      \
+               bool      _overflow = ISC_OVERFLOW_ADD(a, b, &_c); \
+               INSIST(!_overflow);                                \
+               _c;                                                \
+       })
+
+#define ISC_CHECKED_SUB(a, b)                                     \
+       ({                                                        \
+               typeof(a) _c;                                     \
+               bool      _overflow = ISC_OVERFLOW_SUB(a, b, cp); \
+               INSIST(!_overflow);                               \
+               _c;                                               \
+       })
+
+#define ISC_CHECKED_MUL_ADD(a, b, c)                              \
+       ({                                                        \
+               size_t _d;                                        \
+               bool   _overflow = ISC_OVERFLOW_MUL(a, b, &_d) || \
+                                ISC_OVERFLOW_ADD(_d, c, &_d);    \
+               INSIST(!_overflow);                               \
+               _d;                                               \
+       })
index c073061fbc5d08d233eebb5998a8e860194906a5..29285937ead23bdb42d9eb2a08f729be0d6ce43a 100644 (file)
@@ -23,6 +23,7 @@
 #include <time.h>
 
 #include <isc/log.h>
+#include <isc/overflow.h>
 #include <isc/strerr.h>
 #include <isc/string.h>
 #include <isc/time.h>
@@ -186,16 +187,9 @@ isc_time_add(const isc_time_t *t, const isc_interval_t *i, isc_time_t *result) {
        REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC);
 
        /* Seconds */
-#if HAVE_BUILTIN_ADD_OVERFLOW
-       if (__builtin_add_overflow(t->seconds, i->seconds, &result->seconds)) {
+       if (ISC_OVERFLOW_ADD(t->seconds, i->seconds, &result->seconds)) {
                return (ISC_R_RANGE);
        }
-#else
-       if (t->seconds > UINT_MAX - i->seconds) {
-               return (ISC_R_RANGE);
-       }
-       result->seconds = t->seconds + i->seconds;
-#endif
 
        /* Nanoseconds */
        result->nanoseconds = t->nanoseconds + i->nanoseconds;
@@ -217,16 +211,9 @@ isc_time_subtract(const isc_time_t *t, const isc_interval_t *i,
        REQUIRE(t->nanoseconds < NS_PER_SEC && i->nanoseconds < NS_PER_SEC);
 
        /* Seconds */
-#if HAVE_BUILTIN_SUB_OVERFLOW
-       if (__builtin_sub_overflow(t->seconds, i->seconds, &result->seconds)) {
+       if (ISC_OVERFLOW_SUB(t->seconds, i->seconds, &result->seconds)) {
                return (ISC_R_RANGE);
        }
-#else
-       if (t->seconds < i->seconds) {
-               return (ISC_R_RANGE);
-       }
-       result->seconds = t->seconds - i->seconds;
-#endif
 
        /* Nanoseconds */
        if (t->nanoseconds >= i->nanoseconds) {