bind9/lib/isc/include/isc/overflow.h
Tony Finch 7474cad4ad
Add <isc/overflow.h> for checked mul, add, and sub
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.
2023-06-27 12:38:09 +02:00

95 lines
3.4 KiB
C

/*
* 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; \
})