[New-bugs-announce] [issue35752] test_buffer fails on ppc64le: memoryview pack_single() is miscompiled

STINNER Victor report at bugs.python.org
Wed Jan 16 11:51:18 EST 2019

New submission from STINNER Victor <vstinner at redhat.com>:

The bug was first reported on Fedora:

FAIL: test_memoryview_struct_module (test.test_buffer.TestBufferProtocol)
Traceback (most recent call last):
  File "/builddir/build/BUILD/Python-3.6.4/Lib/test/test_buffer.py", line 2540, in test_memoryview_struct_module
    self.assertEqual(m[1], nd[1])
AssertionError: -21.099998474121094 != -21.100000381469727

The problem is the conversion from C double (64-bit float) and C float (32-bit float). There are 2 implementations:

* Objects/memoryobject.c: pack_single() and unpack_single()
* Modules/_struct.c: nu_float() and np_float()

Attached ppc64_float32_bug.py is the simplified test case to trigger the bug.

The result depends on the compiler optimization level:

* gcc -O0: -21.100000381469727 == -21.100000381469727, OK
* gcc -O1: -21.099998474121094 != -21.100000381469727, ERROR
* (I guess that higher optimization level also trigger the bug)

The problem is that the pack_single() function is "miscompiled" (or "too optimized").

Adding "volatile" to PACK_SINGLE() prevents the unsafe compiler optimization and fix the issue for me: try attached pack_single_volatile.patch.

=== -O1 assembler code with the bug ===

PACK_SINGLE(ptr, d, float);

r30 = ptr
(gdb) p $vs63.v2_double
$17 = {0, -21.100000000000001}

=> 0x00000000100a1178 <pack_single+1988>:       stxsspx vs63,0,r30

(gdb) p /x (*ptr)@4
$10 = {0xcc, 0xcc, 0xa8, 0xc1}

The first byte is 0xcc: WRONG.

=== -O1 assembler code without the bug (volatile) ===

r30 = ptr

(gdb) p $f31
$1 = -21.100000000000001

=> 0x00000000100a11e4 <pack_single+2096>:       frsp    f31,f31

(gdb) p $f31
$2 = -21.100000381469727

   0x00000000100a11e8 <pack_single+2100>:       stfs    f31,152(r1)
   0x00000000100a11ec <pack_single+2104>:       lwz     r9,152(r1)

(gdb) p /x $r9
$8 = 0xc1a8cccd

   0x00000000100a11f0 <pack_single+2108>:       stw     r9,0(r30)

(gdb) p /x (*ptr)@4
$9 = {0xcd, 0xcc, 0xa8, 0xc1}

   0x00000000100a11f4 <pack_single+2112>:       li      r3,0
   0x00000000100a11f8 <pack_single+2116>:       lfd     f31,216(r1)
   0x00000000100a11fc <pack_single+2120>:       ld      r30,200(r1)

The first byte is 0xcd: GOOD.

components: Library (Lib)
files: ppc64_float32_bug.py
messages: 333774
nosy: mark.dickinson, skrah, vstinner
priority: normal
severity: normal
status: open
title: test_buffer fails on ppc64le: memoryview pack_single() is miscompiled
versions: Python 3.7, Python 3.8
Added file: https://bugs.python.org/file48060/ppc64_float32_bug.py

Python tracker <report at bugs.python.org>

More information about the New-bugs-announce mailing list