Inaccurate Fmod on i386

Bug #1843205 reported by Alexander Huszagh on 2019-09-09
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
QEMU
Undecided
Unassigned

Bug Description

# Qemu Version

```bash
$ qemu-i386 --version
qemu-i386 version 3.0.1 (qemu-3.0.1-4.fc29)
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
```

# Failing Source Code (C)

```c
#include <math.h>
#include <stdio.h>

int main()
{
    double x = 29860476080414620.0;
    double y = 17.0;
    double z = fmod(x, y);
    printf("%f\n", z);
    return 0;
}
```

The code was compiled with GCC (8.3.1) on x86-64 with the flags `-O3 -m32 -lm -static`.

# Emitted (Annotated) Assembly

In order to facilitate debugging the issue, the following assembly was generated to show nothing unusual occurred during compilation. The assembly was generated with flags `-S -O3 -m32 -lm`, and then annotated to show the operands to fmod.

```asm
 .file "a.c"
 .text
 .section .rodata.str1.1,"aMS",@progbits,1
.LC2:
 .string "%f\n"
 .section .text.startup,"ax",@progbits
 .p2align 4,,15
 .globl main
 .type main, @function
main:
.LFB16:
 .cfi_startproc
 leal 4(%esp), %ecx
 .cfi_def_cfa 1, 0
 andl $-16, %esp
 pushl -4(%ecx)
 pushl %ebp
 .cfi_escape 0x10,0x5,0x2,0x75,0
 movl %esp, %ebp
 pushl %ecx
 .cfi_escape 0xf,0x3,0x75,0x7c,0x6
 subl $4, %esp
 pushl $1076953088 ; high 32-bits of double for y
 pushl $0 ; low 32-bits of double for y
 pushl $1130005884 ; high 32-bits of double for x
 pushl $2003187687 ; low 32-bits of double for x
 call fmod
 movl $.LC2, (%esp)
 fstpl 4(%esp)
 call printf
 movl -4(%ebp), %ecx
 .cfi_def_cfa 1, 0
 addl $16, %esp
 xorl %eax, %eax
 leave
 .cfi_restore 5
 leal -4(%ecx), %esp
 .cfi_def_cfa 4, 4
 ret
 .cfi_endproc
.LFE16:
 .size main, .-main
 .ident "GCC: (GNU) 8.3.1 20190223 (Red Hat 8.3.1-2)"
 .section .note.GNU-stack,"",@progbits
```

# Result

Running the compiled binary on x86_64 produces the expected value of `15.000000`, while using `qemu-i386 <binary>` produces the unexpected result of `-4.000000`.

This was tested against:

1. Qemu 3.0.1 for Fedora 29.
2. Qemu 4.1.0 built from source, downloaded from https://download.qemu.org/qemu-4.1.0.tar.xz
3. Qemu built-from-source against commit 90b1e3afd33226b6078fec6d77a18373712a975c.

# Building Qemu

Qemu built-from-source was compiled as follows:

```bash
mkdir build && cd build
../configure --disable-kvm --target-list="i386-linux-user"
make -j 5
```

# Results

All built versions of Qemu running the 32-bit failed to produce the accurate result. Using qemu-x86_64 against an x86_64 binary built from the same C source code produces correct results. Running the 32-bit binary natively produces the correct result.

tags: added: float libm
removed: fmod
Peter Maydell (pmaydell) wrote :

On current head-of-git QEMU I get the correct answer. I think this was probably fixed by the reimplementation of the 'fprem' emulation in commit 5ef396e2ba86, which was in the 5.1.0 release.

Changed in qemu:
status: New → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers