diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 4f8880dfb8..df2d327213 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -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 index 0000000000..c272cfa879 --- /dev/null +++ b/lib/isc/include/isc/overflow.h @@ -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 + +/* + * 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; \ + }) diff --git a/lib/isc/time.c b/lib/isc/time.c index c073061fbc..29285937ea 100644 --- a/lib/isc/time.c +++ b/lib/isc/time.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -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) {