Commit e81455bb authored by Sergei Golubchik's avatar Sergei Golubchik Committed by Sergey Vojtovich

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
parent a7814d44
...@@ -1025,7 +1025,11 @@ int ulonglong2decimal(ulonglong from, decimal_t *to) ...@@ -1025,7 +1025,11 @@ int ulonglong2decimal(ulonglong from, decimal_t *to)
int longlong2decimal(longlong from, decimal_t *to) int longlong2decimal(longlong from, decimal_t *to)
{ {
if ((to->sign= from < 0)) 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);
}
return ull2dec(from, to); return ull2dec(from, to);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment