diff options
author | Sergei Golubchik <serg@mariadb.org> | 2015-05-04 08:32:05 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2015-05-04 08:32:27 +0200 |
commit | ae18a28500974351cf42fa3cac67c83e0647d510 (patch) | |
tree | 37603a1c1a475554a2cff6eb698cb0bec73dd617 /strings/decimal.c | |
parent | 298368693c43e4ef878b3b01a1ae234cdf94d905 (diff) | |
download | mariadb-git-ae18a28500974351cf42fa3cac67c83e0647d510.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.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/strings/decimal.c b/strings/decimal.c index 979f1b179f9..da47727bd9c 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1024,7 +1024,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); } |