summaryrefslogtreecommitdiff
path: root/strings/decimal.c
diff options
context:
space:
mode:
authorSergei Golubchik <serg@mariadb.org>2015-05-04 08:32:05 +0200
committerSergey Vojtovich <svoj@mariadb.org>2016-07-06 15:17:38 +0400
commite81455bb1617e574faab93f0846a6339064968b3 (patch)
tree50c0eb05525fd942fd95dad7a9f34e07510cf7ec /strings/decimal.c
parenta7814d44fc50ecb270bf9816de7b019a71405e46 (diff)
downloadmariadb-git-e81455bb1617e574faab93f0846a6339064968b3.tar.gz
MDEV-7973 bigint fail with gcc 5.0
-LONGLONG_MIN is the undefined behavior in C. longlong2decimal() used to do this: int longlong2decimal(longlong from, decimal_t *to) { if ((to->sign= from < 0)) return ull2dec(-from, to); return ull2dec(from, to); and later in ull2dec() (DIG_BASE is 1000000000): static int ull2dec(ulonglong from, decimal_t *to) { for (intg1=1; from >= DIG_BASE; intg1++, from/=DIG_BASE) {} this breaks in gcc-5 at -O3. Here ull2dec is inlined into longlong2decimal. And gcc-5 believes that 'from' in the inlined ull2dec is always a positive integer (indeed, if it was negative, then -from was used instead). So gcc-5 uses *signed* comparison with DIG_BASE. Fix: make a special case for LONGLONG_MIN, don't negate it
Diffstat (limited to 'strings/decimal.c')
-rw-r--r--strings/decimal.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/strings/decimal.c b/strings/decimal.c
index 8dbe1bd57f4..b0c57d3db0c 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -1025,7 +1025,11 @@ int ulonglong2decimal(ulonglong from, decimal_t *to)
int longlong2decimal(longlong from, decimal_t *to)
{
if ((to->sign= from < 0))
+ {
+ if (from == LONGLONG_MIN) // avoid undefined behavior
+ return ull2dec((ulonglong)LONGLONG_MIN, to);
return ull2dec(-from, to);
+ }
return ull2dec(from, to);
}