summaryrefslogtreecommitdiff
path: root/strings/decimal.c
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-03-29 09:53:15 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-03-29 09:53:15 +0300
commit020e7d89ebdcded3355c82cec93e0abef2898258 (patch)
tree4e25a2d8826cbe0ddac7ae564fe1c28b220f9925 /strings/decimal.c
parent739002eec90efa73a3b77db1cc46b313e8ac1bfd (diff)
parent303448bc912486f4766129cc407a5077a3ca4359 (diff)
downloadmariadb-git-020e7d89ebdcded3355c82cec93e0abef2898258.tar.gz
Merge 10.2 into 10.3
Diffstat (limited to 'strings/decimal.c')
-rw-r--r--strings/decimal.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 16bc887814a..aa3a78fca24 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1128,13 +1128,21 @@ int decimal2ulonglong(const decimal_t *from, ulonglong *to)
for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
{
- ulonglong y=x;
- x=x*DIG_BASE + *buf++;
- if (unlikely(y > ((ulonglong) ULONGLONG_MAX/DIG_BASE) || x < y))
+ /*
+ Check that the decimal is bigger than any possible integer.
+ Do it before we do the x*=DIB_BASE to avoid integer
+ overflow.
+ */
+ if (unlikely (
+ x >= ULONGLONG_MAX/DIG_BASE &&
+ (x > ULONGLONG_MAX/DIG_BASE ||
+ *buf > (dec1) (ULONGLONG_MAX%DIG_BASE))))
{
*to=ULONGLONG_MAX;
return E_DEC_OVERFLOW;
}
+
+ x=x*DIG_BASE + *buf++;
}
*to=x;
for (frac=from->frac; unlikely(frac > 0); frac-=DIG_PER_DEC1)
@@ -1151,23 +1159,29 @@ int decimal2longlong(const decimal_t *from, longlong *to)
for (intg=from->intg; intg > 0; intg-=DIG_PER_DEC1)
{
- longlong y=x;
/*
+ Check that the decimal is less than any possible integer.
+ Do it before we do the x*=DIB_BASE to avoid integer
+ overflow.
Attention: trick!
we're calculating -|from| instead of |from| here
because |LONGLONG_MIN| > LONGLONG_MAX
- so we can convert -9223372036854775808 correctly
+ so we can convert -9223372036854775808 correctly.
*/
- x=x*DIG_BASE - *buf++;
- if (unlikely(y < (LONGLONG_MIN/DIG_BASE) || x > y))
+ if (unlikely (
+ x <= LONGLONG_MIN/DIG_BASE &&
+ (x < LONGLONG_MIN/DIG_BASE ||
+ *buf > (dec1) (-(LONGLONG_MIN%DIG_BASE)))))
{
/*
- the decimal is bigger than any possible integer
- return border integer depending on the sign
+ the decimal is bigger than any possible integer
+ return border integer depending on the sign
*/
*to= from->sign ? LONGLONG_MIN : LONGLONG_MAX;
return E_DEC_OVERFLOW;
}
+
+ x=x*DIG_BASE - *buf++;
}
/* boundary case: 9223372036854775808 */
if (unlikely(from->sign==0 && x == LONGLONG_MIN))