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

Unit tests segfault on s390x #338

Closed
gotmax23 opened this issue Jan 27, 2023 · 3 comments
Closed

Unit tests segfault on s390x #338

gotmax23 opened this issue Jan 27, 2023 · 3 comments

Comments

@gotmax23
Copy link

Hi. I'm trying to build an orjson RPM package for Fedora Linux. We build for x86_64, i686, powerpc64le, aarch64, and s390x with rustc 1.67.0. orjson's wheel builds successfully for all these arches in our build environment, but its unit tests segfault and crash pytest on s390x. This is likely an endianness issue.

Here is the relevant portion from the full build log. Any help is appreciated.

+ /usr/bin/pytest -vvv
============================= test session starts ==============================
platform linux -- Python 3.11.1, pytest-7.2.0, pluggy-1.0.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /builddir/build/BUILD/orjson-3.8.5
collecting ... collected 828 items

test/test_api.py::TestApi::test_loads_trailing PASSED                    [  0%]
test/test_api.py::TestApi::test_loads_trailing_invalid PASSED            [  0%]
test/test_api.py::TestApi::test_simple_json PASSED                       [  0%]
test/test_api.py::TestApi::test_simple_round_trip PASSED                 [  0%]
test/test_api.py::TestApi::test_loads_type PASSED                        [  0%]
test/test_api.py::TestApi::test_loads_recursion PASSED                   [  0%]
test/test_api.py::TestApi::test_version PASSED                           [  0%]
test/test_api.py::TestApi::test_valueerror PASSED                        [  0%]
test/test_api.py::TestApi::test_optional_none PASSED                     [  1%]
test/test_api.py::TestApi::test_option_not_int PASSED                    [  1%]
test/test_api.py::TestApi::test_option_invalid_int PASSED                [  1%]
test/test_api.py::TestApi::test_option_range_low PASSED                  [  1%]
test/test_api.py::TestApi::test_option_range_high PASSED                 [  1%]
test/test_api.py::TestApi::test_opts_multiple PASSED                     [  1%]
test/test_api.py::TestApi::test_default_positional PASSED                [  1%]
test/test_api.py::TestApi::test_default_unknown_kwarg PASSED             [  1%]
test/test_api.py::TestApi::test_default_empty_kwarg PASSED               [  2%]
test/test_api.py::TestApi::test_default_twice PASSED                     [  2%]
test/test_api.py::TestApi::test_option_twice PASSED                      [  2%]
test/test_api.py::TestApi::test_option_mixed PASSED                      [  2%]
test/test_api.py::TestApi::test_dumps_signature PASSED                   [  2%]
test/test_api.py::TestApi::test_loads_signature PASSED                   [  2%]
test/test_api.py::TestApi::test_dumps_module_str PASSED                  [  2%]
test/test_api.py::TestApi::test_loads_module_str PASSED                  [  2%]
test/test_api.py::TestApi::test_bytes_buffer Fatal Python error: Segmentation fault

Current thread 0x000003ffa5b77720 (most recent call first):
  File "/builddir/build/BUILD/orjson-3.8.5/test/test_api.py", line 213 in test_bytes_buffer
  File "/usr/lib/python3.11/site-packages/_pytest/python.py", line 195 in pytest_pyfunc_call
  File "/usr/lib/python3.11/site-packages/pluggy/_callers.py", line 39 in _multicall
  File "/usr/lib/python3.11/site-packages/pluggy/_manager.py", line 80 in _hookexec
  File "/usr/lib/python3.11/site-packages/pluggy/_hooks.py", line 265 in __call__
  File "/usr/lib/python3.11/site-packages/_pytest/python.py", line 1789 in runtest
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 167 in pytest_runtest_call
  File "/usr/lib/python3.11/site-packages/pluggy/_callers.py", line 39 in _multicall
  File "/usr/lib/python3.11/site-packages/pluggy/_manager.py", line 80 in _hookexec
  File "/usr/lib/python3.11/site-packages/pluggy/_hooks.py", line 265 in __call__
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 260 in <lambda>
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 339 in from_call
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 259 in call_runtest_hook
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 220 in call_and_report
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 131 in runtestprotocol
  File "/usr/lib/python3.11/site-packages/_pytest/runner.py", line 112 in pytest_runtest_protocol
  File "/usr/lib/python3.11/site-packages/pluggy/_callers.py", line 39 in _multicall
  File "/usr/lib/python3.11/site-packages/pluggy/_manager.py", line 80 in _hookexec
  File "/usr/lib/python3.11/site-packages/pluggy/_hooks.py", line 265 in __call__
  File "/usr/lib/python3.11/site-packages/_pytest/main.py", line 349 in pytest_runtestloop
  File "/usr/lib/python3.11/site-packages/pluggy/_callers.py", line 39 in _multicall
  File "/usr/lib/python3.11/site-packages/pluggy/_manager.py", line 80 in _hookexec
  File "/usr/lib/python3.11/site-packages/pluggy/_hooks.py", line 265 in __call__
  File "/usr/lib/python3.11/site-packages/_pytest/main.py", line 324 in _main
  File "/usr/lib/python3.11/site-packages/_pytest/main.py", line 270 in wrap_session
  File "/usr/lib/python3.11/site-packages/_pytest/main.py", line 317 in pytest_cmdline_main
  File "/usr/lib/python3.11/site-packages/pluggy/_callers.py", line 39 in _multicall
  File "/usr/lib/python3.11/site-packages/pluggy/_manager.py", line 80 in _hookexec
  File "/usr/lib/python3.11/site-packages/pluggy/_hooks.py", line 265 in __call__
  File "/usr/lib/python3.11/site-packages/_pytest/config/__init__.py", line 167 in main
  File "/usr/lib/python3.11/site-packages/_pytest/config/__init__.py", line 190 in console_main
  File "/usr/bin/pytest", line 8 in <module>

Extension modules: psutil._psutil_linux, psutil._psutil_posix (total: 2)
/var/tmp/rpm-tmp.eSbesx: line 62:   857 Segmentation fault      (core dumped) CFLAGS="${CFLAGS:-${RPM_OPT_FLAGS}}" LDFLAGS="${LDFLAGS:-${RPM_LD_FLAGS}}" PATH="/builddir/build/BUILDROOT/python-orjson-3.8.5-1.fc38.s390x/usr/bin:$PATH" PYTHONPATH="${PYTHONPATH:-/builddir/build/BUILDROOT/python-orjson-3.8.5-1.fc38.s390x/usr/lib64/python3.11/site-packages:/builddir/build/BUILDROOT/python-orjson-3.8.5-1.fc38.s390x/usr/lib/python3.11/site-packages}" PYTHONDONTWRITEBYTECODE=1 PYTEST_ADDOPTS="${PYTEST_ADDOPTS:-} --ignore=/builddir/build/BUILD/orjson-3.8.5/.pyproject-builddir" PYTEST_XDIST_AUTO_NUM_WORKERS=2 /usr/bin/pytest -vvv
error: Bad exit status from /var/tmp/rpm-tmp.eSbesx (%check)
@decathorpe
Copy link

decathorpe commented Feb 10, 2023

I have tried to narrow down the problem, and it appears that the segfault is caused in Python itself, and not in unsafe Rust code from this project. I found at least one instance of hard-coded constants that are only valid on little-endian systems:
https://github.com/ijl/orjson/blob/master/src/str/ffi.rs#L29-L40

#[cfg(not(Py_3_12))]
const STATE_ASCII: u32 = 0b00000000000000000000000001000000;
#[cfg(not(Py_3_12))]
const STATE_COMPACT: u32 = 0b00000000000000000000000000100000;

#[cfg(Py_3_12)]
const STATE_ASCII: u32 = 0b00000000000000000000000000100000;

#[cfg(Py_3_12)]
const STATE_COMPACT: u32 = 0b00000000000000000000000000010000;

const STATE_COMPACT_ASCII: u32 = STATE_COMPACT | STATE_ASCII;

The values of these bitmasks dressed up as u32s is only correct on little-endian systems but wrong on big-endian systems. I have seen bugs like this one cause crashes of Python before in both rust-python and pyo3:

Both issues are still unresolved (the cpython crate is still crashing, and pyo3 has just removed the affected APIs when building on big-endian systems). The PyASCIIObject.state field in CPython is defined as a bitfield here:

https://github.com/python/cpython/blob/v3.11.2/Include/cpython/unicodeobject.h#L149-L204

The exact positions of these flags will be different on little-endian and big-endian architectures, but I think it should be possible to map this C bitfield to a Rust bitmask correctly (the indices for the different fields will just be different depending on LE or BE).


EDIT: Oh, and of course, what's even worse: The memory layout of bitfields is not standardized, with most aspects being "implementation defined" in the C standards.

@ijl
Copy link
Owner

ijl commented Feb 28, 2023

Thanks for the report. The problem is shown by adding s390x to the linux-cross CI job. I would merge a patch that passes that.

@ijl ijl closed this as completed Feb 28, 2023
@gotmax23
Copy link
Author

gotmax23 commented Mar 4, 2023

This is still not fixed with 3.8.7. The tests segfault at the exact same place. Please reopen the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants