Re: SIGFPE with gcc 7.3.0 in sqlite3: fldl instruction underflow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

El mié., 21 nov. 2018 a las 15:46, Thomas De Schampheleire
(<patrickdepinguin@xxxxxxxxx>) escribió:
>
> Hello,
>
> I have a problem with a program that links with sqlite3 and executes
> an SQL statement. The program is executed under Qemu, with an 32-bit
> x86 emulated machine, and Qemu is running on a 64-bit x86 host.
>
> Originally, the program worked fine, when it was compiled with a
> toolchain composed out of gcc 4.9.2, glibc 2.21, binutils 2.24.
>
> Now I am rebuilding the system with a toolchain composed out of gcc
> 7.3, glibc 2.27, binutils 2.30. In this case, the program receives a
> SIGFPE (Arithmetic Error) in Sqlite code. Analysis of the coredump
> reveals that the error occurs on an 'fldl' instruction (Floating-point
> Load Long) and that the exact cause of the error is an underflow.
>
> The problem does not appear when Qemu is started without KVM support.
> In this case, floating point handling is covered by Qemu itself. The
> problem does occur when passing '-enable-kvm' which causes the host
> machine to execute most instructions.
>
> However, it is unclear to me why gcc is emitting an 'fldl' instruction
> here (which wasn't present with the old toolchain) and why it is
> causing an underflow. The part of the code being executed is not
> handling a floating-point value.
> There is a print of a real a bit further down, which is conditional on
> a flag indicating that the union indeed holds a real value. Could this
> 'fldl' instruction be part of that code, moved upwards? In that case,
> who is at fault here? Because the loading of the real should only
> happen when we know that it is indeed a real, and not an integer.

It seems I was right here: gcc optimization caused the floating-point
load to move upwards, before the checking if the union value is
actually of floating-point type. This optimization can cause a
floating-point exception.

If I add a compiler barrier between the checking of the flag and the
reading of the value, then the problem is gone. No floating-point
exception occurs (because the value is actually of type int).

Modified code is:

  if( fg & MEM_Int ){
    sqlite3_snprintf(nByte, pMem->z, "%lld", pMem->u.i);
  }else{
    assert( fg & MEM_Real );
    asm volatile("" ::: "memory");
    sqlite3_snprintf(nByte, pMem->z, "%!.15g", pMem->u.r);
  }

My question now becomes: is gcc allowed to optimize here (without the barrier)?
Is gcc allowed to pre-load the floating point value pMem->u.r if it
does not know yet that the value in the union is a floating-point
value, knowing that a load of an invalid (integer) value could cause
floating-point exceptions like underflow?

Thanks,
Thomas




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux