Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: overflow.h,v 1.3 2026/04/08 00:16:16 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #pragma once
     17 
     18 #include <isc/util.h>
     19 
     20 /*
     21  * It is awkward to support signed numbers as well, so keep it simple
     22  * (with a safety check).
     23  */
     24 #define ISC_OVERFLOW_IS_UNSIGNED(a)                                      \
     25 	({                                                               \
     26 		STATIC_ASSERT((typeof(a))-1 > 0,                         \
     27 			      "overflow checks require unsigned types"); \
     28 		(a);                                                     \
     29 	})
     30 
     31 #define ISC_OVERFLOW_UINT_MAX(a) ISC_OVERFLOW_IS_UNSIGNED((typeof(a))-1)
     32 
     33 #define ISC_OVERFLOW_UINT_MIN(a) ISC_OVERFLOW_IS_UNSIGNED(0)
     34 
     35 /*
     36  * Return true on overflow, e.g.
     37  *
     38  *	bool overflow = ISC_OVERFLOW_MUL(count, sizeof(array[0]), &bytes);
     39  *	INSIST(!overflow);
     40  */
     41 
     42 #if HAVE_BUILTIN_MUL_OVERFLOW
     43 #define ISC_OVERFLOW_MUL(a, b, cp) __builtin_mul_overflow(a, b, cp)
     44 #else
     45 #define ISC_OVERFLOW_MUL(a, b, cp)                                           \
     46 	((ISC_OVERFLOW_UINT_MAX(a) / (b) > (a)) ? (*(cp) = (a) * (b), false) \
     47 						: true)
     48 #endif
     49 
     50 #if HAVE_BUILTIN_ADD_OVERFLOW
     51 #define ISC_OVERFLOW_ADD(a, b, cp) __builtin_add_overflow(a, b, cp)
     52 #else
     53 #define ISC_OVERFLOW_ADD(a, b, cp)                                           \
     54 	((ISC_OVERFLOW_UINT_MAX(a) - (b) > (a)) ? (*(cp) = (a) + (b), false) \
     55 						: true)
     56 #endif
     57 
     58 #if HAVE_BUILTIN_SUB_OVERFLOW
     59 #define ISC_OVERFLOW_SUB(a, b, cp) __builtin_sub_overflow(a, b, cp)
     60 #else
     61 #define ISC_OVERFLOW_SUB(a, b, cp)                                           \
     62 	((ISC_OVERFLOW_UINT_MIN(a) + (b) < (a)) ? (*(cp) = (a) - (b), false) \
     63 						: true)
     64 #endif
     65 
     66 #define ISC_CHECKED_MUL(a, b)                                      \
     67 	({                                                         \
     68 		typeof(a) _c;                                      \
     69 		bool	  _overflow = ISC_OVERFLOW_MUL(a, b, &_c); \
     70 		INSIST(!_overflow);                                \
     71 		_c;                                                \
     72 	})
     73 
     74 #define ISC_CHECKED_ADD(a, b)                                      \
     75 	({                                                         \
     76 		typeof(a) _c;                                      \
     77 		bool	  _overflow = ISC_OVERFLOW_ADD(a, b, &_c); \
     78 		INSIST(!_overflow);                                \
     79 		_c;                                                \
     80 	})
     81 
     82 #define ISC_CHECKED_SUB(a, b)                                     \
     83 	({                                                        \
     84 		typeof(a) _c;                                     \
     85 		bool	  _overflow = ISC_OVERFLOW_SUB(a, b, cp); \
     86 		INSIST(!_overflow);                               \
     87 		_c;                                               \
     88 	})
     89 
     90 #define ISC_CHECKED_MUL_ADD(a, b, c)                              \
     91 	({                                                        \
     92 		size_t _d;                                        \
     93 		bool   _overflow = ISC_OVERFLOW_MUL(a, b, &_d) || \
     94 				   ISC_OVERFLOW_ADD(_d, c, &_d);  \
     95 		INSIST(!_overflow);                               \
     96 		_d;                                               \
     97 	})
     98