diff --git a/src/expr.c b/src/expr.c index f45afb72..65060522 100644 --- a/src/expr.c +++ b/src/expr.c @@ -783,12 +783,11 @@ static int Add(void) /* If both are ints, just add 'em */ if (v2.type == INT_TYPE && v1.type == INT_TYPE) { - int old = v1.v.val; - v1.v.val += v2.v.val; /* Check for overflow */ - if (_private_add_overflow(v1.v.val, v2.v.val, old)) { + if (_private_add_overflow(v1.v.val, v2.v.val)) { return E_2HIGH; } + v1.v.val += v2.v.val; PushValStack(v1); return OK; } @@ -796,9 +795,8 @@ static int Add(void) /* If it's a date plus an int, add 'em */ if ((v1.type == DATE_TYPE && v2.type == INT_TYPE) || (v1.type == INT_TYPE && v2.type == DATE_TYPE)) { - int old = v1.v.val; + if (_private_add_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val += v2.v.val; - if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; if (v1.v.val < 0) return E_DATE_OVER; v1.type = DATE_TYPE; PushValStack(v1); @@ -808,9 +806,8 @@ static int Add(void) /* If it's a datetime plus an int or a time, add 'em */ if ((v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) || ((v1.type == INT_TYPE || v1.type == TIME_TYPE) && v2.type == DATETIME_TYPE)) { - int old = v1.v.val; + if (_private_add_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val += v2.v.val; - if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; if (v1.v.val < 0) return E_DATE_OVER; v1.type = DATETIME_TYPE; PushValStack(v1); @@ -822,9 +819,8 @@ static int Add(void) if ((v1.type == TIME_TYPE && v2.type == INT_TYPE) || (v1.type == INT_TYPE && v2.type == TIME_TYPE) || (v1.type == TIME_TYPE && v2.type == TIME_TYPE)) { - int old = v1.v.val; + if (_private_add_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val += v2.v.val; - if (_private_add_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; v1.v.val = v1.v.val % MINUTES_PER_DAY; if (v1.v.val < 0) v1.v.val += MINUTES_PER_DAY; v1.type = TIME_TYPE; @@ -885,18 +881,16 @@ static int Subtract(void) /* If they're both INTs, do subtraction */ if (v1.type == INT_TYPE && v2.type == INT_TYPE) { - int old = v1.v.val; + if (_private_sub_overflow(v1.v.val, v2.v.val)) return E_2HIGH; v1.v.val -= v2.v.val; - if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_2HIGH; PushValStack(v1); return OK; } /* If it's a date minus an int, do subtraction, checking for underflow */ if (v1.type == DATE_TYPE && v2.type == INT_TYPE) { - int old = v1.v.val; + if (_private_sub_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val -= v2.v.val; - if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; if (v1.v.val < 0) return E_DATE_OVER; PushValStack(v1); return OK; @@ -905,9 +899,8 @@ static int Subtract(void) /* If it's a datetime minus an int or a time, do subtraction, * checking for underflow */ if (v1.type == DATETIME_TYPE && (v2.type == INT_TYPE || v2.type == TIME_TYPE)) { - int old = v1.v.val; + if (_private_sub_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val -= v2.v.val; - if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; if (v1.v.val < 0) return E_DATE_OVER; PushValStack(v1); return OK; @@ -925,9 +918,8 @@ static int Subtract(void) if ((v1.type == TIME_TYPE && v2.type == TIME_TYPE) || (v1.type == DATETIME_TYPE && v2.type == DATETIME_TYPE) || (v1.type == DATE_TYPE && v2.type == DATE_TYPE)) { - int old = v1.v.val; + if (_private_sub_overflow(v1.v.val, v2.v.val)) return E_DATE_OVER; v1.v.val -= v2.v.val; - if (_private_sub_overflow(v1.v.val, v2.v.val, old)) return E_DATE_OVER; v1.type = INT_TYPE; PushValStack(v1); return OK; @@ -962,11 +954,8 @@ static int Multiply(void) (v1.v.val == -1 && v2.v.val == INT_MIN)) { return E_2HIGH; } - int old = v1.v.val; + if (_private_mul_overflow(v1.v.val, v2.v.val)) return E_2HIGH; v1.v.val *= v2.v.val; - if (v2.v.val != 0) { - if (_private_div(v1.v.val, v2.v.val) != old) return E_2HIGH; - } PushValStack(v1); return OK; } @@ -1177,9 +1166,8 @@ static int UnMinus(void) { Value *v = &ValStack[ValStackPtr-1]; if (v->type != INT_TYPE) return E_BAD_TYPE; - int old = v->v.val; + if (v->v.val == INT_MIN) return E_2HIGH; v->v.val = -v->v.val; - if (_private_unminus_overflow(old, v->v.val)) return E_2HIGH; return OK; } diff --git a/src/expr.h b/src/expr.h index 68b6d8ee..c9c5be9d 100644 --- a/src/expr.h +++ b/src/expr.h @@ -58,7 +58,7 @@ else \ in various arithmetic operators. They have to be in separate functions with extern linkage to defeat compiler optimizations that would otherwise break the overflow checks. */ -extern int _private_div(int a, int b); -extern int _private_add_overflow(int result, int b, int old); -extern int _private_sub_overflow(int result, int b, int old); -extern int _private_unminus_overflow(int a, int b); +extern int _private_mul_overflow(int a, int b); +extern int _private_add_overflow(int a, int b); +extern int _private_sub_overflow(int a, int b); + diff --git a/src/utils.c b/src/utils.c index d9a2eae8..39f70381 100644 --- a/src/utils.c +++ b/src/utils.c @@ -130,24 +130,33 @@ int DateOK(int y, int m, int d) /* Functions designed to defeat gcc optimizer */ -int _private_div(int a, int b) { return a/b; } -int _private_add_overflow(int result, int b, int old) +int _private_mul_overflow(int a, int b) { - if (b > 0 && result < old) return 1; - if (b < 0 && result > old) return 1; - return 0; -} -int _private_sub_overflow(int result, int b, int old) -{ - if (b < 0 && result < old) return 1; - if (b > 0 && result > old) return 1; + double aa = (double) a; + double bb = (double) b; + + if (aa*bb > (double) INT_MAX || aa*bb < (double) INT_MIN) { + return 1; + } return 0; } -int _private_unminus_overflow(int a, int b) +int _private_add_overflow(int a, int b) { - if (a > 0 && b > 0) return 1; - if (a < 0 && b < 0) return 1; + double aa = (double) a; + double bb = (double) b; + + if (aa+bb < (double) INT_MIN) return 1; + if (aa+bb > (double) INT_MAX) return 1; + return 0; +} +int _private_sub_overflow(int a, int b) +{ + double aa = (double) a; + double bb = (double) b; + + if (aa-bb < (double) INT_MIN) return 1; + if (aa-bb > (double) INT_MAX) return 1; return 0; }