Inaccurate Fmod on i386

Bug #1843205 reported by Alexander Huszagh
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
QEMU
Fix Released
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: float libm
tags: added: float libm
removed: fmod
Revision history for this message
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  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.