codekingpro/portable-devtools
115k
1/*-------------------------------------------------------------------------2 *3 * int.h4 * Routines to perform integer math, while checking for overflows.5 *6 * The routines in this file are intended to be well defined C, without7 * relying on compiler flags like -fwrapv.8 *9 * To reduce the overhead of these routines try to use compiler intrinsics10 * where available. That's not that important for the 16, 32 bit cases, but11 * the 64 bit cases can be considerably faster with intrinsics. In case no12 * intrinsics are available 128 bit math is used where available.13 *14 * Copyright (c) 2017-2023, PostgreSQL Global Development Group15 *16 * src/include/common/int.h17 *18 *-------------------------------------------------------------------------19 */20#ifndef COMMON_INT_H21#define COMMON_INT_H22 23 24/*---------25 * The following guidelines apply to all the routines:26 * - If a + b overflows, return true, otherwise store the result of a + b27 * into *result. The content of *result is implementation defined in case of28 * overflow.29 * - If a - b overflows, return true, otherwise store the result of a - b30 * into *result. The content of *result is implementation defined in case of31 * overflow.32 * - If a * b overflows, return true, otherwise store the result of a * b33 * into *result. The content of *result is implementation defined in case of34 * overflow.35 *---------36 */37 38/*------------------------------------------------------------------------39 * Overflow routines for signed integers40 *------------------------------------------------------------------------41 */42 43/*44 * INT1645 */46static inline bool47pg_add_s16_overflow(int16 a, int16 b, int16 *result)48{49#if defined(HAVE__BUILTIN_OP_OVERFLOW)50 return __builtin_add_overflow(a, b, result);51#else52 int32 res = (int32) a + (int32) b;53 54 if (res > PG_INT16_MAX || res < PG_INT16_MIN)55 {56 *result = 0x5EED; /* to avoid spurious warnings */57 return true;58 }59 *result = (int16) res;60 return false;61#endif62}63 64static inline bool65pg_sub_s16_overflow(int16 a, int16 b, int16 *result)66{67#if defined(HAVE__BUILTIN_OP_OVERFLOW)68 return __builtin_sub_overflow(a, b, result);69#else70 int32 res = (int32) a - (int32) b;71 72 if (res > PG_INT16_MAX || res < PG_INT16_MIN)73 {74 *result = 0x5EED; /* to avoid spurious warnings */75 return true;76 }77 *result = (int16) res;78 return false;79#endif80}81 82static inline bool83pg_mul_s16_overflow(int16 a, int16 b, int16 *result)84{85#if defined(HAVE__BUILTIN_OP_OVERFLOW)86 return __builtin_mul_overflow(a, b, result);87#else88 int32 res = (int32) a * (int32) b;89 90 if (res > PG_INT16_MAX || res < PG_INT16_MIN)91 {92 *result = 0x5EED; /* to avoid spurious warnings */93 return true;94 }95 *result = (int16) res;96 return false;97#endif98}99 100/*101 * INT32102 */103static inline bool104pg_add_s32_overflow(int32 a, int32 b, int32 *result)105{106#if defined(HAVE__BUILTIN_OP_OVERFLOW)107 return __builtin_add_overflow(a, b, result);108#else109 int64 res = (int64) a + (int64) b;110 111 if (res > PG_INT32_MAX || res < PG_INT32_MIN)112 {113 *result = 0x5EED; /* to avoid spurious warnings */114 return true;115 }116 *result = (int32) res;117 return false;118#endif119}120 121static inline bool122pg_sub_s32_overflow(int32 a, int32 b, int32 *result)123{124#if defined(HAVE__BUILTIN_OP_OVERFLOW)125 return __builtin_sub_overflow(a, b, result);126#else127 int64 res = (int64) a - (int64) b;128 129 if (res > PG_INT32_MAX || res < PG_INT32_MIN)130 {131 *result = 0x5EED; /* to avoid spurious warnings */132 return true;133 }134 *result = (int32) res;135 return false;136#endif137}138 139static inline bool140pg_mul_s32_overflow(int32 a, int32 b, int32 *result)141{142#if defined(HAVE__BUILTIN_OP_OVERFLOW)143 return __builtin_mul_overflow(a, b, result);144#else145 int64 res = (int64) a * (int64) b;146 147 if (res > PG_INT32_MAX || res < PG_INT32_MIN)148 {149 *result = 0x5EED; /* to avoid spurious warnings */150 return true;151 }152 *result = (int32) res;153 return false;154#endif155}156 157/*158 * INT64159 */160static inline bool161pg_add_s64_overflow(int64 a, int64 b, int64 *result)162{163#if defined(HAVE__BUILTIN_OP_OVERFLOW)164 return __builtin_add_overflow(a, b, result);165#elif defined(HAVE_INT128)166 int128 res = (int128) a + (int128) b;167 168 if (res > PG_INT64_MAX || res < PG_INT64_MIN)169 {170 *result = 0x5EED; /* to avoid spurious warnings */171 return true;172 }173 *result = (int64) res;174 return false;175#else176 if ((a > 0 && b > 0 && a > PG_INT64_MAX - b) ||177 (a < 0 && b < 0 && a < PG_INT64_MIN - b))178 {179 *result = 0x5EED; /* to avoid spurious warnings */180 return true;181 }182 *result = a + b;183 return false;184#endif185}186 187static inline bool188pg_sub_s64_overflow(int64 a, int64 b, int64 *result)189{190#if defined(HAVE__BUILTIN_OP_OVERFLOW)191 return __builtin_sub_overflow(a, b, result);192#elif defined(HAVE_INT128)193 int128 res = (int128) a - (int128) b;194 195 if (res > PG_INT64_MAX || res < PG_INT64_MIN)196 {197 *result = 0x5EED; /* to avoid spurious warnings */198 return true;199 }200 *result = (int64) res;201 return false;202#else203 /*204 * Note: overflow is also possible when a == 0 and b < 0 (specifically,205 * when b == PG_INT64_MIN).206 */207 if ((a < 0 && b > 0 && a < PG_INT64_MIN + b) ||208 (a >= 0 && b < 0 && a > PG_INT64_MAX + b))209 {210 *result = 0x5EED; /* to avoid spurious warnings */211 return true;212 }213 *result = a - b;214 return false;215#endif216}217 218static inline bool219pg_mul_s64_overflow(int64 a, int64 b, int64 *result)220{221#if defined(HAVE__BUILTIN_OP_OVERFLOW)222 return __builtin_mul_overflow(a, b, result);223#elif defined(HAVE_INT128)224 int128 res = (int128) a * (int128) b;225 226 if (res > PG_INT64_MAX || res < PG_INT64_MIN)227 {228 *result = 0x5EED; /* to avoid spurious warnings */229 return true;230 }231 *result = (int64) res;232 return false;233#else234 /*235 * Overflow can only happen if at least one value is outside the range236 * sqrt(min)..sqrt(max) so check that first as the division can be quite a237 * bit more expensive than the multiplication.238 *239 * Multiplying by 0 or 1 can't overflow of course and checking for 0240 * separately avoids any risk of dividing by 0. Be careful about dividing241 * INT_MIN by -1 also, note reversing the a and b to ensure we're always242 * dividing it by a positive value.243 *244 */245 if ((a > PG_INT32_MAX || a < PG_INT32_MIN ||246 b > PG_INT32_MAX || b < PG_INT32_MIN) &&247 a != 0 && a != 1 && b != 0 && b != 1 &&248 ((a > 0 && b > 0 && a > PG_INT64_MAX / b) ||249 (a > 0 && b < 0 && b < PG_INT64_MIN / a) ||250 (a < 0 && b > 0 && a < PG_INT64_MIN / b) ||251 (a < 0 && b < 0 && a < PG_INT64_MAX / b)))252 {253 *result = 0x5EED; /* to avoid spurious warnings */254 return true;255 }256 *result = a * b;257 return false;258#endif259}260 261/*------------------------------------------------------------------------262 * Overflow routines for unsigned integers263 *------------------------------------------------------------------------264 */265 266/*267 * UINT16268 */269static inline bool270pg_add_u16_overflow(uint16 a, uint16 b, uint16 *result)271{272#if defined(HAVE__BUILTIN_OP_OVERFLOW)273 return __builtin_add_overflow(a, b, result);274#else275 uint16 res = a + b;276 277 if (res < a)278 {279 *result = 0x5EED; /* to avoid spurious warnings */280 return true;281 }282 *result = res;283 return false;284#endif285}286 287static inline bool288pg_sub_u16_overflow(uint16 a, uint16 b, uint16 *result)289{290#if defined(HAVE__BUILTIN_OP_OVERFLOW)291 return __builtin_sub_overflow(a, b, result);292#else293 if (b > a)294 {295 *result = 0x5EED; /* to avoid spurious warnings */296 return true;297 }298 *result = a - b;299 return false;300#endif301}302 303static inline bool304pg_mul_u16_overflow(uint16 a, uint16 b, uint16 *result)305{306#if defined(HAVE__BUILTIN_OP_OVERFLOW)307 return __builtin_mul_overflow(a, b, result);308#else309 uint32 res = (uint32) a * (uint32) b;310 311 if (res > PG_UINT16_MAX)312 {313 *result = 0x5EED; /* to avoid spurious warnings */314 return true;315 }316 *result = (uint16) res;317 return false;318#endif319}320 321/*322 * INT32323 */324static inline bool325pg_add_u32_overflow(uint32 a, uint32 b, uint32 *result)326{327#if defined(HAVE__BUILTIN_OP_OVERFLOW)328 return __builtin_add_overflow(a, b, result);329#else330 uint32 res = a + b;331 332 if (res < a)333 {334 *result = 0x5EED; /* to avoid spurious warnings */335 return true;336 }337 *result = res;338 return false;339#endif340}341 342static inline bool343pg_sub_u32_overflow(uint32 a, uint32 b, uint32 *result)344{345#if defined(HAVE__BUILTIN_OP_OVERFLOW)346 return __builtin_sub_overflow(a, b, result);347#else348 if (b > a)349 {350 *result = 0x5EED; /* to avoid spurious warnings */351 return true;352 }353 *result = a - b;354 return false;355#endif356}357 358static inline bool359pg_mul_u32_overflow(uint32 a, uint32 b, uint32 *result)360{361#if defined(HAVE__BUILTIN_OP_OVERFLOW)362 return __builtin_mul_overflow(a, b, result);363#else364 uint64 res = (uint64) a * (uint64) b;365 366 if (res > PG_UINT32_MAX)367 {368 *result = 0x5EED; /* to avoid spurious warnings */369 return true;370 }371 *result = (uint32) res;372 return false;373#endif374}375 376/*377 * UINT64378 */379static inline bool380pg_add_u64_overflow(uint64 a, uint64 b, uint64 *result)381{382#if defined(HAVE__BUILTIN_OP_OVERFLOW)383 return __builtin_add_overflow(a, b, result);384#else385 uint64 res = a + b;386 387 if (res < a)388 {389 *result = 0x5EED; /* to avoid spurious warnings */390 return true;391 }392 *result = res;393 return false;394#endif395}396 397static inline bool398pg_sub_u64_overflow(uint64 a, uint64 b, uint64 *result)399{400#if defined(HAVE__BUILTIN_OP_OVERFLOW)401 return __builtin_sub_overflow(a, b, result);402#else403 if (b > a)404 {405 *result = 0x5EED; /* to avoid spurious warnings */406 return true;407 }408 *result = a - b;409 return false;410#endif411}412 413static inline bool414pg_mul_u64_overflow(uint64 a, uint64 b, uint64 *result)415{416#if defined(HAVE__BUILTIN_OP_OVERFLOW)417 return __builtin_mul_overflow(a, b, result);418#elif defined(HAVE_INT128)419 uint128 res = (uint128) a * (uint128) b;420 421 if (res > PG_UINT64_MAX)422 {423 *result = 0x5EED; /* to avoid spurious warnings */424 return true;425 }426 *result = (uint64) res;427 return false;428#else429 uint64 res = a * b;430 431 if (a != 0 && b != res / a)432 {433 *result = 0x5EED; /* to avoid spurious warnings */434 return true;435 }436 *result = res;437 return false;438#endif439}440 441#endif /* COMMON_INT_H */442 