From e81455bb1617e574faab93f0846a6339064968b3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 4 May 2015 08:32:05 +0200 Subject: [PATCH] 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 --- strings/decimal.c | 4 ++++ 1 file changed, 4 insertions(+) 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); }