diff options
Diffstat (limited to 'src/backend/utils/adt/numeric.c')
-rw-r--r-- | src/backend/utils/adt/numeric.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 1bfa29e1b28..1667d8093f1 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -5789,9 +5789,15 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, * to avoid normalizing carries immediately. * * maxdig tracks the maximum possible value of any dig[] entry; when this - * threatens to exceed INT_MAX, we take the time to propagate carries. To - * avoid overflow in maxdig itself, it actually represents the max - * possible value divided by NBASE-1. + * threatens to exceed INT_MAX, we take the time to propagate carries. + * Furthermore, we need to ensure that overflow doesn't occur during the + * carry propagation passes either. The carry values could be as much as + * INT_MAX/NBASE, so really we must normalize when digits threaten to + * exceed INT_MAX - INT_MAX/NBASE. + * + * To avoid overflow in maxdig itself, it actually represents the max + * possible value divided by NBASE-1, ie, at the top of the loop it is + * known that no dig[] entry exceeds maxdig * (NBASE-1). */ dig = (int *) palloc0(res_ndigits * sizeof(int)); maxdig = 0; @@ -5806,7 +5812,7 @@ mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result, /* Time to normalize? */ maxdig += var1digit; - if (maxdig > INT_MAX / (NBASE - 1)) + if (maxdig > (INT_MAX - INT_MAX / NBASE) / (NBASE - 1)) { /* Yes, do it */ carry = 0; |