Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test_ctypes.test_generated_structs.GeneratedTest.test_generated_data 'ManyTypesU' fails on Python 3.14 built with gcc 15 #128889

Closed
befeleme opened this issue Jan 15, 2025 · 14 comments
Assignees
Labels
3.14 new features, bugs and security fixes tests Tests in the Lib/test dir topic-ctypes type-bug An unexpected behavior, bug, or error

Comments

@befeleme
Copy link
Contributor

befeleme commented Jan 15, 2025

Bug report

Bug description:

When running test suite on Python 3.14.0a4 built with gcc 15.0.3 on Fedora Linux 42 (Rawhide), test_generated_data fails for many of its types.
I suspect this is due to the new gcc version. This doesn't happen when Python is built with gcc 14.

Check that a ctypes struct/union matches its C equivalent. ... 
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i8', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i8', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i8', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u8', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u8', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u8', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i16', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i16', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i16', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u16', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u16', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u16', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i32', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i32', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i32', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u32', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u32', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u32', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL

Example output:

FAIL: test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='i8', value=-1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/builddir/build/BUILD/python3.14-3.14.0_a4-build/Python-3.14.0a4/Lib/test/test_ctypes/test_generated_structs.py", line 473, in test_generated_data
    self.assertEqual(py_mem.hex(), c_mem.hex(), m)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 'ff00000000000000' != 'ff8f8783ffff0000'
- ff00000000000000
+ ff8f8783ffff0000
 : <FieldInfo for ManyTypesU.i8: <Field type=c_int8, ofs=0, size=1>>
in:
union {
    int8_t i8;
    uint8_t u8;
    int16_t i16;
    uint16_t u16;
    int32_t i32;
    uint32_t u32;
    int64_t i64;
    uint64_t u64;
}

Ran 1 test in 0.178s
FAILED (failures=18, skipped=11)

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

@befeleme befeleme added the type-bug An unexpected behavior, bug, or error label Jan 15, 2025
@vstinner
Copy link
Member

cc @encukou

@davidmalcolm
Copy link
Member

@hroncok
Copy link
Contributor

hroncok commented Jan 15, 2025

I was gonna report that the failures do not occur with Python 3.13 -- only to realize the tests do not exist there either.

@davidmalcolm
Copy link
Member

The failures in test_ctypes occurred for me on all archs I tried on (aarch64, ppc64le, s390x, x86_64) with gcc-15.0.0-0.2.fc42, from upstream gcc source 2024-12-03 revision d2b3fd44a4b20c573bb9c8ef5b17bdca70ea748b).

Build logs are currently here:
https://copr.fedorainfracloud.org/coprs/dmalcolm/gcc-15-smoketest-3.failed/build/8477142/

@davidmalcolm
Copy link
Member

The package was built with 4 different configurations: "debug", "optimized", "freethreading-debug", "freethreading".

Trying manually, test_ctypes succeeds with "optimized" and "freethreading", but fails with "debug" and "freethreading-debug".

(the package build tries "debug" first in %check, and the failure there causes a fatal error of the package build without trying the other configs)

@davidmalcolm
Copy link
Member

Something I did locally has fixed it, FWIW I was trying to regenerate Modules/_ctypes/_ctypes_test_generated.c.h and somehow it now works for all 4 configurations.

I'm not sure what I did that "fixed" it.

@ZeroIntensity ZeroIntensity added tests Tests in the Lib/test dir topic-ctypes 3.14 new features, bugs and security fixes labels Jan 16, 2025
@encukou
Copy link
Member

encukou commented Jan 16, 2025

Thanks for the report! I set some time aside for ctypes each week; I'll look into this soon.
Feel free to skip the tests in Fedora for now.

Thanks for the cc, Victor! @befeleme, you can mention me directly on anything ctypes related :)

@encukou encukou self-assigned this Jan 16, 2025
@davidmalcolm
Copy link
Member

davidmalcolm commented Jan 16, 2025

Hacking in some test prints and looking at the py_mem vs c_mem, it looks like the test is being over-zealous about the result.

For example here:

  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u8', value=1, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
field=<FieldInfo for ManyTypesU.u8: <Field type=c_uint8, ofs=0, size=1>>, value=0
py_mem=b'\x00\x00\x00\x00\x00\x00\x00\x00'
 c_mem=b'\x00\xca\xb6\xff\xfc\x7f\x00\x00'

...I see that the byte[0] is the same in both.

In here, with ofs=0, size=2:

  test_generated_data (test.test_ctypes.test_generated_structs.GeneratedTest.test_generated_data) (field='u8', value=0, name='ManyTypesU')
Check that a ctypes struct/union matches its C equivalent. ... FAIL
field=<FieldInfo for ManyTypesU.i16: <Field type=c_int16, ofs=0, size=2>>, value=-1
py_mem=b'\xff\xff\x00\x00\x00\x00\x00\x00'
 c_mem=b'\xff\xff\xb6\xff\xfc\x7f\x00\x00'

I see that bytes[0] and [1] are indeed the same in both.

The docstring has this:

    This does depend on the C compiler keeping padding bits zero.
    Common compilers seem to do so.

which perhaps GCC 15 isn't doing in some cases (not sure; haven't reliably reproduced this).

@davidmalcolm
Copy link
Member

Possibly relates to this new GCC 15 optimization: expr, c: Don't clear whole unions relating to GCC bug 116416.

If so (though I haven't proven this), a workaround might be to use -fzero-init-padding-bits=unions (which is new in GCC 15, added by that patch).

@davidmalcolm davidmalcolm changed the title test_ctypes.test_generated_structs.GeneratedTest.test_generated_data fails on Python 3.14 built with gcc 15 test_ctypes.test_generated_structs.GeneratedTest.test_generated_data 'ManyTypesU' fails on Python 3.14 built with gcc 15 Jan 16, 2025
@davidmalcolm
Copy link
Member

Yes: if I recompile Modules/_ctypes/_ctypes_test.o

  • with -fzero-init-padding-bits=unions or -fzero-init-padding-bits=all, the test passes;
  • with -fzero-init-padding-bits=standard, the test fails.

@davidmalcolm
Copy link
Member

davidmalcolm commented Jan 16, 2025

Note that -fzero-init-padding-bits=standard is the default, and, as noted above the test case fails with this.

See: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fzero-init-padding-bits_003dvalue

@encukou
Copy link
Member

encukou commented Jan 17, 2025

I tried reproducing using the dmalcolm/gcc-15-smoketest-3.failed COPR in a container, but couldn't get the bug to show up.

@davidmalcolm or @befeleme, could you test with #128944? Looks like a memset should solve this case.

Hacking in some test prints and looking at the py_mem vs c_mem, it looks like the test is being over-zealous about the result.

Thanks! Yeah, I'm aware the tests don't play by the book. I'm (slowly) adding infrastructure to make them better.

The test writes a struct field, in both Python/ctypes and in C, and checks that the operation has the same result.
It checks all of the memory, because for bitfields (and so, in general), we don't really know where a field is -- the test is checking that we guessed the position correctly.

@vstinner
Copy link
Member

I built Python manually on Fedora Rawhide (in mock) but I failed to reproduce the test_ctypes failure. I tested gcc (GCC) 15.0.1 20250114 (Red Hat 15.0.1-0) and built Python with:

./configure && make -j12
./python -m test -v test_ctypes

@vstinner
Copy link
Member

Oh ok, I managed to reproduce the issue: Python must be built with gcc -O0. Commands to reproduce the issue:

./configure --with-pydebug CFLAGS="-O0"
make -j12
./python -m test test_ctypes.test_generated_structs -v

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.14 new features, bugs and security fixes tests Tests in the Lib/test dir topic-ctypes type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

6 participants