diff --git a/src/bignum.h b/src/bignum.h index 981b310571eefe1e950149fe4d690f22e4654233..659aa7a6f9b9ed41f93f39dca28bbec16b2182d0 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -20,172 +20,223 @@ * The second uses manual multiplication for unsigned multiply or checks for overflow * as recommended in * https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow + * When using clang with builtin support for checking arithmetic overflow, those builtins will + * be used. + * These functions will also detect and try to avoid undefined behavior, e.g. shifts of + * negative integers. */ - -#define _GEN_OF2(type, type2, utype2, size) \ -static INLINE type DO_ ## type ## _ADD_OVERFLOW(type a, type b, int * of) { \ - type2 res; \ - res = (type2)a + (type2)b; \ - if (res < MIN_ ## type || res > MAX_ ## type) \ - *of = 1; \ - return (type)res; \ -} \ -static INLINE type DO_ ## type ## _SUB_OVERFLOW(type a, type b, int * of) { \ - type2 res; \ - res = (type2)a - (type2)b; \ - if (res < MIN_ ## type || res > MAX_ ## type) \ - *of = 1; \ - return (type)res; \ -} \ -static INLINE type DO_ ## type ## _MUL_OVERFLOW(type a, type b, int * of) { \ - type2 res; \ - res = (type2)a * (type2)b; \ - if (res < MIN_ ## type || res > MAX_ ## type) \ - *of = 1; \ - return (type)res; \ -} \ -static INLINE type DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \ - int * of) { \ - utype2 res; \ - res = (utype2)a + (utype2)b; \ - *of |= !!(res >> size); \ - return (unsigned type)res; \ -} \ -static INLINE type DO_U ## type ## _SUB_OVERFLOW(unsigned type a, unsigned type b, \ - int * of) { \ - utype2 res; \ - res = (utype2)a - (utype2)b; \ - *of |= !!(res >> size); \ - return (unsigned type)res; \ -} \ -static INLINE type DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \ - int * of) { \ - utype2 res; \ - res = (utype2)a * (utype2)b; \ - *of |= !!(res >> size); \ - return (unsigned type)res; \ +#define GENERIC_OVERFLOW_CHECKS(type) \ +static INLINE int DO_## type ## _NEG_OVERFLOW(type a, type * res) { \ + if (a == MIN_ ## type) return 1; \ + *res = -a; \ + return 0; \ +} \ +static INLINE int type ## _NEG_OVERFLOW(type a) { \ + return a == MIN_ ## type; \ +} \ +static INLINE int type ## _DIV_OVERFLOW(type a, type b) { \ + return a == MIN_ ## type && b == -1; \ +} \ +static INLINE int DO_ ## type ## _DIV_OVERFLOW(type a, type b, type * res) { \ + if (a == MIN_ ## type && b == -1) return 1; \ + *res = a/b; \ + return 0; \ +} \ +static INLINE int U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b) { \ + unsigned type res; \ + return DO_U ## type ## _MUL_OVERFLOW(a, b, &res); \ +} \ +static INLINE int U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b) { \ + unsigned type res; \ + return DO_U ## type ## _ADD_OVERFLOW(a, b, &res); \ +} \ +static INLINE int U ## type ## _SUB_OVERFLOW(unsigned type a, unsigned type b) { \ + unsigned type res; \ + return DO_U ## type ## _SUB_OVERFLOW(a, b, &res); \ +} \ +static INLINE int type ## _MUL_OVERFLOW(type a, type b) { \ + type res; \ + return DO_ ## type ## _MUL_OVERFLOW(a, b, &res); \ +} \ +static INLINE int type ## _ADD_OVERFLOW(type a, type b) { \ + type res; \ + return DO_ ## type ## _ADD_OVERFLOW(a, b, &res); \ +} \ +static INLINE int type ## _SUB_OVERFLOW(type a, type b) { \ + type res; \ + return DO_ ## type ## _SUB_OVERFLOW(a, b, &res); \ +} \ +static INLINE int type ## _MOD_OVERFLOW(type a, type b) { \ + return type ## _DIV_OVERFLOW(a, b); \ +} \ +static INLINE int DO_ ## type ## _MOD_OVERFLOW(type a, type b, type * res) { \ + if (type ## _MOD_OVERFLOW(a, b)) { \ + return 1; \ + } \ + *res = a % b; \ + return 0; \ +} \ +static INLINE int type ## _LSH_OVERFLOW(type a, type b) { \ + type size = (type)sizeof(type)*CHAR_BIT; \ + return (b < 0 || b >= size - 1 || a < 0 || (b && (a >> (size - 1 - b)))); \ +} \ +static INLINE int type ## _RSH_OVERFLOW(type a, type b) { \ + return (b < 0 || a < 0 || b >= (type)sizeof(type)*CHAR_BIT); \ +} \ +static INLINE int DO_ ## type ## _LSH_OVERFLOW(type a, type b, type * res) { \ + if (type ## _LSH_OVERFLOW(a, b)) return 1; \ + *res = a << b; \ + return 0; \ +} \ +static INLINE int DO_ ## type ## _RSH_OVERFLOW(type a, type b, type * res) { \ + if (type ## _RSH_OVERFLOW(a, b)) return 1; \ + *res = a >> b; \ + return 0; \ } -#define _GEN_OF1(type, size) \ -static INLINE type DO_ ## type ## _ADD_OVERFLOW(type a, type b, int * of) { \ - if ((b > 0 && a > MAX_ ## type - b) || \ - (b < 0 && a < MIN_ ## type - b)) \ - *of = 1; \ - return a + b; \ -} \ -static INLINE type DO_ ## type ## _SUB_OVERFLOW(type a, type b, int * of) { \ - if ((b > 0 && a < MIN_ ## type + b) || \ - (b < 0 && a > MAX_ ## type + b)) \ - *of = 1; \ - return a - b; \ -} \ -static INLINE type DO_## type ## _MUL_OVERFLOW(type a, type b, int * of) { \ - if (a > 0) { \ - if (b > 0) { \ - if (a > (MAX_ ## type / b)) { \ - *of = 1; \ - } \ - } else { \ - if (b < (MIN_ ## type / a)) { \ - *of = 1; \ - } \ - } \ - } else { \ - if (b > 0) { \ - if (a < (MAX_ ## type / b)) { \ - *of = 1; \ - } \ - } else { \ - if ( (a != 0) && (b < (MAX_ ## type / a))) { \ - *of = 1; \ - } \ - } \ - } \ - return a*b; \ -} \ -static INLINE type DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \ - int * of) { \ - if (a > MAX_U ## type - b) \ - *of = 1; \ - return a + b; \ -} \ -static INLINE type DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \ - int * of) { \ - unsigned type res = 0; \ - unsigned type bits = size/2; \ - unsigned type low_mask = ((1 << bits)-1); \ - unsigned type a1 = a >> bits; \ - unsigned type b1 = b >> bits; \ - unsigned type a0 = a & low_mask; \ - unsigned type b0 = b & low_mask; \ - res = a1 * b1; \ - a1 *= b0; \ - b1 *= a0; \ - if (res || (a1|b1) & ~low_mask) *of = 1; \ - res = a1<<bits; \ - res = DO_U ## type ## _ADD_OVERFLOW(res, b1<<bits, of); \ - res = DO_U ## type ## _ADD_OVERFLOW(res, a0*b0, of); \ - return res; \ -} \ +#if PIKE_CLANG_BUILTIN(__builtin_uadd_overflow) +#define DO_INT32_ADD_OVERFLOW __builtin_sadd_overflow +#define DO_INT32_SUB_OVERFLOW __builtin_ssub_overflow +#define DO_INT32_MUL_OVERFLOW __builtin_smul_overflow +#define DO_UINT32_ADD_OVERFLOW __builtin_uadd_overflow +#define DO_UINT32_SUB_OVERFLOW __builtin_usub_overflow +#define DO_UINT32_MUL_OVERFLOW __builtin_umul_overflow +#define DO_INT64_ADD_OVERFLOW __builtin_saddl_overflow +#define DO_INT64_SUB_OVERFLOW __builtin_ssubl_overflow +#define DO_INT64_MUL_OVERFLOW __builtin_smull_overflow +#define DO_UINT64_ADD_OVERFLOW __builtin_uaddl_overflow +#define DO_UINT64_SUB_OVERFLOW __builtin_usubl_overflow +#define DO_UINT64_MUL_OVERFLOW __builtin_umull_overflow + +GENERIC_OVERFLOW_CHECKS(INT32) +#if defined(INT64) +GENERIC_OVERFLOW_CHECKS(INT64) +#endif -#define _GEN_OF_CHECK(type) \ -static INLINE type DO_## type ## _NEG_OVERFLOW(type a, int * of) { \ - *of |= (a == MIN_ ## type); \ - return -a; \ -} \ -static INLINE int type ## _NEG_OVERFLOW(type a) { \ - return a == MIN_ ## type; \ -} \ -static INLINE int type ## _DIV_OVERFLOW(type a, type b) { \ - return a == MIN_ ## type && b == -1; \ -} \ -static INLINE type DO_ ## type ## _DIV_OVERFLOW(type a, type b, int * of) { \ - *of |= a == MIN_ ## type && b == -1; \ - return a/b; \ -} \ -static INLINE int U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b) { \ - int of = 0; \ - DO_U ## type ## _MUL_OVERFLOW(a, b, &of); \ - return of; \ -} \ -static INLINE int U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b) { \ - int of = 0; \ - DO_U ## type ## _ADD_OVERFLOW(a, b, &of); \ - return of; \ -} \ -static INLINE int type ## _MUL_OVERFLOW(type a, type b) { \ - int of = 0; \ - DO_ ## type ## _MUL_OVERFLOW(a, b, &of); \ - return of; \ -} \ -static INLINE int type ## _ADD_OVERFLOW(type a, type b) { \ - int of = 0; \ - DO_ ## type ## _ADD_OVERFLOW(a, b, &of); \ - return of; \ -} \ -static INLINE int type ## _SUB_OVERFLOW(type a, type b) { \ - int of = 0; \ - DO_ ## type ## _SUB_OVERFLOW(a, b, &of); \ - return of; \ -} \ -static INLINE int type ## _MOD_OVERFLOW(type a, type b) { \ - return type ## _DIV_OVERFLOW(a, b); \ -} \ -static INLINE type DO_ ## type ## _MOD_OVERFLOW(type a, type b, int * of) { \ - if (type ## _MOD_OVERFLOW(a, b)) { \ - *of = 1; \ - return 0; \ - } \ - return a % b; \ +#else +#define _GEN_OF2(type, type2, utype2, size) \ +static INLINE int DO_ ## type ## _ADD_OVERFLOW(type a, type b, type * res) { \ + type2 tmp; \ + tmp = (type2)a + (type2)b; \ + if (tmp < MIN_ ## type || tmp > MAX_ ## type) \ + return 1; \ + *res = (type)tmp; \ + return 0; \ +} \ +static INLINE int DO_ ## type ## _SUB_OVERFLOW(type a, type b, type * res) { \ + type2 tmp; \ + tmp = (type2)a - (type2)b; \ + if (tmp < MIN_ ## type || tmp > MAX_ ## type) \ + return 1; \ + *res = (type)tmp; \ + return 0; \ +} \ +static INLINE int DO_ ## type ## _MUL_OVERFLOW(type a, type b, type * res) { \ + type2 tmp; \ + tmp = (type2)a * (type2)b; \ + if (tmp < MIN_ ## type || tmp > MAX_ ## type) \ + return 1; \ + *res = (type)tmp; \ + return 0; \ +} \ +static INLINE int DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \ + unsigned type * res) { \ + utype2 tmp; \ + tmp = (utype2)a + (utype2)b; \ + if (tmp >> size) return 1; \ + *res = (unsigned type)tmp; \ + return 0; \ +} \ +static INLINE int DO_U ## type ## _SUB_OVERFLOW(unsigned type a, unsigned type b, \ + unsigned type * res) { \ + utype2 tmp; \ + tmp = (utype2)a - (utype2)b; \ + if (tmp >> size) return 1; \ + *res = (unsigned type)tmp; \ + return 0; \ +} \ +static INLINE int DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \ + unsigned type * res) { \ + utype2 tmp; \ + tmp = (utype2)a * (utype2)b; \ + if (tmp >> size) return 1; \ + *res = (unsigned type)tmp; \ + return 0; \ } +#define _GEN_OF1(type, size) \ +static INLINE int DO_ ## type ## _ADD_OVERFLOW(type a, type b, type * res) { \ + if ((b > 0 && a > MAX_ ## type - b) || \ + (b < 0 && a < MIN_ ## type - b)) \ + return 1; \ + *res = a + b; \ + return 0; \ +} \ +static INLINE int DO_ ## type ## _SUB_OVERFLOW(type a, type b, type * res) { \ + if ((b > 0 && a < MIN_ ## type + b) || \ + (b < 0 && a > MAX_ ## type + b)) \ + return 1; \ + *res = a - b; \ + return 0; \ +} \ +static INLINE int DO_## type ## _MUL_OVERFLOW(type a, type b, type * res) { \ + if (a > 0) { \ + if (b > 0) { \ + if (a > (MAX_ ## type / b)) { \ + return 1; \ + } \ + } else { \ + if (b < (MIN_ ## type / a)) { \ + return 1; \ + } \ + } \ + } else { \ + if (b > 0) { \ + if (a < (MAX_ ## type / b)) { \ + return 1; \ + } \ + } else { \ + if ( (a != 0) && (b < (MAX_ ## type / a))) { \ + return 1; \ + } \ + } \ + } \ + *res = a * b; \ + return 0; \ +} \ +static INLINE int DO_U ## type ## _ADD_OVERFLOW(unsigned type a, unsigned type b, \ + unsigned type * res) { \ + if (a > MAX_U ## type - b) \ + return 1; \ + *res = a + b; \ + return 0; \ +} \ +static INLINE int DO_U ## type ## _MUL_OVERFLOW(unsigned type a, unsigned type b, \ + unsigned type * res) { \ + unsigned type tmp = 0; \ + unsigned type bits = size/2; \ + unsigned type low_mask = ((1 << bits)-1); \ + unsigned type a1 = a >> bits; \ + unsigned type b1 = b >> bits; \ + unsigned type a0 = a & low_mask; \ + unsigned type b0 = b & low_mask; \ + tmp = a1 * b1; \ + a1 *= b0; \ + b1 *= a0; \ + if (tmp || (a1|b1) & ~low_mask) return 1; \ + tmp = a1<<bits; \ + if (DO_U ## type ## _ADD_OVERFLOW(tmp, b1<<bits, &tmp) \ + || DO_U ## type ## _ADD_OVERFLOW(tmp, a0*b0, &tmp)) return 1; \ + *res = tmp; \ + return 0; \ +} \ #define GEN_OF1(size) \ _GEN_OF1(INT ## size, size) \ - _GEN_OF_CHECK(INT ## size) + GENERIC_OVERFLOW_CHECKS(INT ## size) #define GEN_OF2(s1, s2) \ _GEN_OF2(INT ## s1, INT ## s2, UINT ## s2, s1) \ - _GEN_OF_CHECK(INT ## s1) + GENERIC_OVERFLOW_CHECKS(INT ## s1) #if defined(INT128) && defined(UINT128) GEN_OF2(64, 128) @@ -197,6 +248,8 @@ GEN_OF2(32, 64) GEN_OF1(32) #endif +#endif + #if SIZEOF_INT_TYPE == 8 #define INT_TYPE_MUL_OVERFLOW INT64_MUL_OVERFLOW #define INT_TYPE_ADD_OVERFLOW INT64_ADD_OVERFLOW @@ -204,12 +257,16 @@ GEN_OF1(32) #define INT_TYPE_NEG_OVERFLOW INT64_NEG_OVERFLOW #define INT_TYPE_DIV_OVERFLOW INT64_DIV_OVERFLOW #define INT_TYPE_MOD_OVERFLOW INT64_MOD_OVERFLOW +#define INT_TYPE_LSH_OVERFLOW INT64_LSH_OVERFLOW +#define INT_TYPE_RSH_OVERFLOW INT64_RSH_OVERFLOW #define DO_INT_TYPE_MUL_OVERFLOW DO_INT64_MUL_OVERFLOW #define DO_INT_TYPE_ADD_OVERFLOW DO_INT64_ADD_OVERFLOW #define DO_INT_TYPE_SUB_OVERFLOW DO_INT64_SUB_OVERFLOW #define DO_INT_TYPE_NEG_OVERFLOW DO_INT64_NEG_OVERFLOW #define DO_INT_TYPE_DIV_OVERFLOW DO_INT64_DIV_OVERFLOW #define DO_INT_TYPE_MOD_OVERFLOW DO_INT64_MOD_OVERFLOW +#define DO_INT_TYPE_LSH_OVERFLOW DO_INT64_LSH_OVERFLOW +#define DO_INT_TYPE_RSH_OVERFLOW DO_INT64_RSH_OVERFLOW #elif SIZEOF_INT_TYPE == 4 #define INT_TYPE_MUL_OVERFLOW INT32_MUL_OVERFLOW #define INT_TYPE_ADD_OVERFLOW INT32_ADD_OVERFLOW @@ -217,24 +274,18 @@ GEN_OF1(32) #define INT_TYPE_NEG_OVERFLOW INT32_NEG_OVERFLOW #define INT_TYPE_DIV_OVERFLOW INT32_DIV_OVERFLOW #define INT_TYPE_MOD_OVERFLOW INT32_MOD_OVERFLOW +#define INT_TYPE_LSH_OVERFLOW INT32_LSH_OVERFLOW +#define INT_TYPE_RSH_OVERFLOW INT32_RSH_OVERFLOW #define DO_INT_TYPE_MUL_OVERFLOW DO_INT32_MUL_OVERFLOW #define DO_INT_TYPE_ADD_OVERFLOW DO_INT32_ADD_OVERFLOW #define DO_INT_TYPE_SUB_OVERFLOW DO_INT32_SUB_OVERFLOW #define DO_INT_TYPE_NEG_OVERFLOW DO_INT32_NEG_OVERFLOW #define DO_INT_TYPE_DIV_OVERFLOW DO_INT32_DIV_OVERFLOW #define DO_INT_TYPE_MOD_OVERFLOW DO_INT32_MOD_OVERFLOW -#else -#error Bad size of INT_TYPE +#define DO_INT_TYPE_LSH_OVERFLOW DO_INT32_LSH_OVERFLOW +#define DO_INT_TYPE_RSH_OVERFLOW DO_INT32_RSH_OVERFLOW #endif -#define INT_TYPE_LSH_OVERFLOW(a, b) \ - ((((INT_TYPE)sizeof(INT_TYPE))*CHAR_BIT <= (b) && (a)) || \ - (((a)<<(b))>>(b)) != (a)) - -/* Note: If this gives overflow, set the result to zero. */ -#define INT_TYPE_RSH_OVERFLOW(a, b) \ - (((INT_TYPE)sizeof(INT_TYPE))*CHAR_BIT <= (b) && (a)) - /* Prototypes begin here */ PMOD_EXPORT extern struct svalue auto_bignum_program; PMOD_EXPORT struct program *get_auto_bignum_program(void); diff --git a/src/lexer.h b/src/lexer.h index b52e42387d173624f52d686331666928635aea26..917d874052b2d7ff750ccfc97a33f68f9330e37b 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -194,6 +194,7 @@ int parse_esc_seq (WCHAR *buf, p_wchar2 *chr, ptrdiff_t *len) { ptrdiff_t l = 1; p_wchar2 c; + int of = 0; switch ((c = *buf)) { @@ -212,13 +213,17 @@ int parse_esc_seq (WCHAR *buf, p_wchar2 *chr, ptrdiff_t *len) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { - int of = 0; unsigned INT32 n = c-'0'; for (l = 1; buf[l] >= '0' && buf[l] <= '8'; l++) { - n = DO_UINT32_MUL_OVERFLOW(n, 8, &of); - n += buf[l] - '0'; + if (DO_UINT32_MUL_OVERFLOW(n, 8, &n)) + of = 1; + else + n += buf[l] - '0'; + } + if (of) { + *len = l; + return 4; } - if (of) {*len = l; return 4;} c = (p_wchar2)n; break; } @@ -229,45 +234,56 @@ int parse_esc_seq (WCHAR *buf, p_wchar2 *chr, ptrdiff_t *len) break; case 'x': { - int of = 0; unsigned INT32 n=0; for (l = 1;; l++) { switch (buf[l]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - n = DO_UINT32_MUL_OVERFLOW(n, 16, &of); - n += buf[l] - '0'; + if (DO_UINT32_MUL_OVERFLOW(n, 16, &n)) + of = 1; + else + n += buf[l] - '0'; continue; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - n = DO_UINT32_MUL_OVERFLOW(n, 16, &of); - n += buf[l] - 'a' + 10; + if (DO_UINT32_MUL_OVERFLOW(n, 16, &n)) + of = 1; + else + n += buf[l] - 'a' + 10; continue; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - n = DO_UINT32_MUL_OVERFLOW(n, 16, &of); - n += buf[l] - 'A' + 10; + if (DO_UINT32_MUL_OVERFLOW(n, 16, &n)) + of = 1; + else + n += buf[l] - 'A' + 10; continue; } break; } - if (of) {*len = l; return 5;} + if (of) { + *len = l; + return 5; + } c = (p_wchar2)n; break; } case 'd': { - int of = 0; unsigned INT32 n=0; for (l = 1;; l++) { switch (buf[l]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - n = DO_UINT32_MUL_OVERFLOW(n, 10, &of); - n = DO_UINT32_ADD_OVERFLOW(n, buf[l] - '0', &of); + if (DO_UINT32_MUL_OVERFLOW(n, 10, &n) || DO_UINT32_ADD_OVERFLOW(n, buf[l] - '0', &n)) { + of = 1; + } continue; } break; } - if (of) {*len = l; return 6;} + if (of) { + *len = l; + return 6; + } c = (p_wchar2)n; break; } diff --git a/src/operators.c b/src/operators.c index a1cfc62c47b1f28ca1dd520e6d451f0b0d6f6443..01e0fea820143b9893601873e0e78dc83c9e244e 100644 --- a/src/operators.c +++ b/src/operators.c @@ -1726,13 +1726,12 @@ PMOD_EXPORT void f_add(INT32 args) size = 0; for(e = -args; e < 0; e++) { - size = DO_INT_TYPE_ADD_OVERFLOW(size, sp[e].u.integer, &of); - } - if(of) - { - convert_svalue_to_bignum(sp-args); - f_add(args); - return; + if (DO_INT_TYPE_ADD_OVERFLOW(size, sp[e].u.integer, &size)) + { + convert_svalue_to_bignum(sp-args); + f_add(args); + return; + } } sp-=args; push_int(size); @@ -3721,11 +3720,8 @@ PMOD_EXPORT void o_multiply(void) case TWO_TYPES(T_INT,T_INT): { INT_TYPE res; - int of = 0; - - res = DO_INT_TYPE_MUL_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer, &of); - if(of) + if (DO_INT_TYPE_MUL_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer, &res)) { convert_stack_top_to_bignum(); goto do_lfun_multiply; @@ -4291,21 +4287,21 @@ do_lfun_modulo: res = a % b; }else{ /* res = ((a+~b)%-b)-~b */ - res = DO_INT_TYPE_ADD_OVERFLOW(a, ~b, &of); - res = DO_INT_TYPE_MOD_OVERFLOW(res, b, &of); - res = DO_INT_TYPE_SUB_OVERFLOW(res, ~b, &of); + of = DO_INT_TYPE_ADD_OVERFLOW(a, ~b, &res) + || DO_INT_TYPE_MOD_OVERFLOW(res, b, &res) + || DO_INT_TYPE_SUB_OVERFLOW(res, ~b, &res); } }else{ if(b>=0) { /* res = b+~((~a) % b) */ - res = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &of); - res = DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &of); + of = DO_INT_TYPE_MOD_OVERFLOW(~a, b, &res) + || DO_INT_TYPE_ADD_OVERFLOW(b, ~res, &res); }else{ /* a % b and a % -b are equivalent, if overflow does not * happen * res = -(-a % -b) = a % b; */ - res = DO_INT_TYPE_MOD_OVERFLOW(a, b, &of); + of = DO_INT_TYPE_MOD_OVERFLOW(a, b, &res); } } if (of) { diff --git a/src/port.h b/src/port.h index 8ca98965f6fdc6f8a8f031bec2fdd91e4daea022..4cee558705e9a9b5caea969aad896ee59c8f2a47 100644 --- a/src/port.h +++ b/src/port.h @@ -432,4 +432,12 @@ double LDEXP(double x, int exp); void _dosmaperr(int x); #endif +#ifdef __clang__ +#define PIKE_CLANG_FEATURE(x) __has_feature(x) +#define PIKE_CLANG_BUILTIN(x) __has_builtin(x) +#else +#define PIKE_CLANG_FEATURE(x) (0) +#define PIKE_CLANG_BUILTIN(x) (0) +#endif + #endif