Thanks to visit codestin.com
Credit goes to github.com

Skip to content

BUG: Segfault in trimesh's test suite with numpy 1.26.0b1 #24459

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

Closed
mgorny opened this issue Aug 19, 2023 · 6 comments · Fixed by #24484
Closed

BUG: Segfault in trimesh's test suite with numpy 1.26.0b1 #24459

mgorny opened this issue Aug 19, 2023 · 6 comments · Fixed by #24484

Comments

@mgorny
Copy link
Contributor

mgorny commented Aug 19, 2023

Describe the issue:

When running the test suite of trimesh package (as of 3.23.3) against numpy 1.26.0b1, I'm getting a segfault (details below). This problem doesn't occur with 1.25.2, so I suspect it might be a regression in the beta.

I've reproduced the problem with Python 3.10.12 and 3.11.4, using both numpy installed from wheels and built using Gentoo packages. The tracebacks below are done using the Gentoo package built with -O0 -ggdb.

CC @mikedh

Reproduce the code example:

git clone https://github.com/mikedh/trimesh/
cd trimesh
git checkout 3.23.3
python3.11 -m venv .venv
. .venv/bin/activate
pip install -e . numpy==1.26.0b1 pytest
python -m pytest tests/test_cache.py::CacheTest::test_method_combinations

Error message:

(gdb) run
Starting program: /tmp/portage/dev-python/trimesh-3.23.3/work/trimesh-3.23.3-python3_10/install/usr/bin/python3.10 -m pytest tests/test_cache.py::CacheTest::test_method_combinations
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
========================================================= test session starts =========================================================
platform linux -- Python 3.10.12, pytest-7.4.0, pluggy-1.2.0
rootdir: /tmp/portage/dev-python/trimesh-3.23.3/work/trimesh-3.23.3
collecting ... [Detaching after vfork from child process 65533]
[Detaching after vfork from child process 65534]
[Detaching after vfork from child process 65535]
[Detaching after vfork from child process 65536]
[Detaching after vfork from child process 65539]
collected 1 item                                                                                                                      

tests/test_cache.py 
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff5bb2b36 in NPY_cast_info_xfree (cast_info=0x7ffffffd9dc0)
    at ../numpy-1.26.0b1/numpy/core/src/multiarray/dtype_transfer.h:62
#2  0x00007ffff5bb67d2 in PyArray_Choose (ip=0x7ffff64380c0, op=[3, -1], out=0x0, clipmode=NPY_RAISE)
    at ../numpy-1.26.0b1/numpy/core/src/multiarray/item_selection.c:1122
#3  0x00007ffff5bd2d87 in array_choose (self=0x7ffff64380c0, args=([3, -1],), kwds=0x0)
    at ../numpy-1.26.0b1/numpy/core/src/multiarray/methods.c:1333
#4  0x00007ffff7b31dba in cfunction_call (func=<built-in method choose of TrackedArray object at remote 0x7ffff64380c0>, 
    args=([3, -1],), kwargs=0x0) at Objects/methodobject.c:543
#5  0x00007ffff7addcb9 in _PyObject_Call (tstate=0x555555577520, 
    callable=<built-in method choose of TrackedArray object at remote 0x7ffff64380c0>, args=([3, -1],), kwargs=0x0)
    at Objects/call.c:305
#6  0x00007ffff7addd19 in PyObject_Call (callable=<built-in method choose of TrackedArray object at remote 0x7ffff64380c0>, 
    args=([3, -1],), kwargs=0x0) at Objects/call.c:317
#7  0x00007ffff7bf48f5 in do_call_core (tstate=0x555555577520, trace_info=0x7ffffffdad60, 
    func=<built-in method choose of TrackedArray object at remote 0x7ffff64380c0>, callargs=([3, -1],), kwdict=0x0)
    at Python/ceval.c:5917
#8  0x00007ffff7bf015e in _PyEval_EvalFrameDefault (tstate=0x555555577520, 
    f=Frame 0x7ff7eb8fa750, for file <string>, line 1, in <module> (), throwflag=0) at Python/ceval.c:4277
#9  0x00007ffff7be218a in _PyEval_EvalFrame (tstate=0x555555577520, 
    f=Frame 0x7ff7eb8fa750, for file <string>, line 1, in <module> (), throwflag=0) at ./Include/internal/pycore_ceval.h:46
#10 0x00007ffff7bf29e7 in _PyEval_Vector (tstate=0x555555577520, con=0x7ffffffdaea0, 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated), args=0x0, argcount=0, 
    kwnames=0x0) at Python/ceval.c:5067
#11 0x00007ffff7be486d in PyEval_EvalCode (co=<code at remote 0x7ff7ebcffe10>, 
    globals={'__name__': 'tests.test_cache', '__doc__': None, '__package__': 'tests', '__loader__': <AssertionRewritingHook(config=<Config(option=<Namespace(keyword='', markexpr='', maxfail=0, continue_on_collection_errors=False, confcutdir=None, noconftest=False, keepduplicates=False, collect_in_virtualenv=False, importmode='prepend', basetemp=None, durations=None, durations_min=<float at remote 0x7ffff69f12f0>, version=0, plugins=[], traceconfig=False, showfixtures=False, show_fixtures_per_test=False, verbose=0, no_header=False, no_summary=False, reportchars='fE', disable_warnings=False, showlocals=False, tbstyle='auto', showcapture='all', fulltrace=False, color='auto', code_highlight='yes', capture='fd', runxfail=False, pastebin=None, assertmode='rewrite', xmlpath=None, junitprefix=None, doctestmodules=False, doctestreport='udiff', doctestglob=[], doctest_ignore_import_errors=False, doctest_continue_on_failure=False, last_failed_no_failures='all', stepwise=False, stepwise_skip=False, logger_disable=[], markers=False, ...(truncated), 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated)) at Python/ceval.c:1134
#12 0x00007ffff7c49a7f in run_eval_code_obj (tstate=0x555555577520, co=0x7ff7ebcffe10, 
    globals={'__name__': 'tests.test_cache', '__doc__': None, '__package__': 'tests', '__loader__': <AssertionRewritingHook(config=<Config(option=<Namespace(keyword='', markexpr='', maxfail=0, continue_on_collection_errors=False, confcutdir=None, noconftest=False, keepduplicates=False, collect_in_virtualenv=False, importmode='prepend', basetemp=None, durations=None, durations_min=<float at remote 0x7ffff69f12f0>, version=0, plugins=[], traceconfig=False, showfixtures=False, show_fixtures_per_test=False, verbose=0, no_header=False, no_summary=False, reportchars='fE', disable_warnings=False, showlocals=False, tbstyle='auto', showcapture='all', fulltrace=False, color='auto', code_highlight='yes', capture='fd', runxfail=False, pastebin=None, assertmode='rewrite', xmlpath=None, junitprefix=None, doctestmodules=False, doctestreport='udiff', doctestglob=[], doctest_ignore_import_errors=False, doctest_continue_on_failure=False, last_failed_no_failures='all', stepwise=False, stepwise_skip=False, logger_disable=[], markers=False, ...(truncated), 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated)) at Python/pythonrun.c:1291
#13 0x00007ffff7c49b6b in run_mod (mod=0x555556ebc108, filename='<string>', 
    globals={'__name__': 'tests.test_cache', '__doc__': None, '__package__': 'tests', '__loader__': <AssertionRewritingHook(config=<Config(option=<Namespace(keyword='', markexpr='', maxfail=0, continue_on_collection_errors=False, confcutdir=None, noconftest=False, keepduplicates=False, collect_in_virtualenv=False, importmode='prepend', basetemp=None, durations=None, durations_min=<float at remote 0x7ffff69f12f0>, version=0, plugins=[], traceconfig=False, showfixtures=False, show_fixtures_per_test=False, verbose=0, no_header=False, no_summary=False, reportchars='fE', disable_warnings=False, showlocals=False, tbstyle='auto', showcapture='all', fulltrace=False, color='auto', code_highlight='yes', capture='fd', runxfail=False, pastebin=None, assertmode='rewrite', xmlpath=None, junitprefix=None, doctestmodules=False, doctestreport='udiff', doctestglob=[], doctest_ignore_import_errors=False, doctest_continue_on_failure=False, last_failed_no_failures='all', stepwise=False, stepwise_skip=False, logger_disable=[], markers=False, ...(truncated), 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated), flags=0x7ffffffdb040, 
    arena=0x7ff7eb8f1bd0) at Python/pythonrun.c:1312
#14 0x00007ffff7c49784 in PyRun_StringFlags (str=0x7ff7eb73dd60 "m.choose(*A)", start=258, 
    globals={'__name__': 'tests.test_cache', '__doc__': None, '__package__': 'tests', '__loader__': <AssertionRewritingHook(config=<Config(option=<Namespace(keyword='', markexpr='', maxfail=0, continue_on_collection_errors=False, confcutdir=None, noconftest=False, keepduplicates=False, collect_in_virtualenv=False, importmode='prepend', basetemp=None, durations=None, durations_min=<float at remote 0x7ffff69f12f0>, version=0, plugins=[], traceconfig=False, showfixtures=False, show_fixtures_per_test=False, verbose=0, no_header=False, no_summary=False, reportchars='fE', disable_warnings=False, showlocals=False, tbstyle='auto', showcapture='all', fulltrace=False, color='auto', code_highlight='yes', capture='fd', runxfail=False, pastebin=None, assertmode='rewrite', xmlpath=None, junitprefix=None, doctestmodules=False, doctestreport='udiff', doctestglob=[], doctest_ignore_import_errors=False, doctest_continue_on_failure=False, last_failed_no_failures='all', stepwise=False, stepwise_skip=False, logger_disable=[], markers=False, ...(truncated), 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated), flags=0x7ffffffdb040)
    at Python/pythonrun.c:1183
#15 0x00007ffff7bde276 in builtin_eval_impl (module=<module at remote 0x7ffff7198900>, source='m.choose(*A)', 
    globals={'__name__': 'tests.test_cache', '__doc__': None, '__package__': 'tests', '__loader__': <AssertionRewritingHook(config=<Config(option=<Namespace(keyword='', markexpr='', maxfail=0, continue_on_collection_errors=False, confcutdir=None, noconftest=False, keepduplicates=False, collect_in_virtualenv=False, importmode='prepend', basetemp=None, durations=None, durations_min=<float at remote 0x7ffff69f12f0>, version=0, plugins=[], traceconfig=False, showfixtures=False, show_fixtures_per_test=False, verbose=0, no_header=False, no_summary=False, reportchars='fE', disable_warnings=False, showlocals=False, tbstyle='auto', showcapture='all', fulltrace=False, color='auto', code_highlight='yes', capture='fd', runxfail=False, pastebin=None, assertmode='rewrite', xmlpath=None, junitprefix=None, doctestmodules=False, doctestreport='udiff', doctestglob=[], doctest_ignore_import_errors=False, doctest_continue_on_failure=False, last_failed_no_failures='all', stepwise=False, stepwise_skip=False, logger_disable=[], markers=False, ...(truncated), 
    locals={'self': <CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_ScopeName'}, __doc__='\n    Represents one of the possible fixture scopes in pytest.\n\n    Scop...(truncated)) at Python/bltinmodule.c:982
#16 0x00007ffff7bdc0be in builtin_eval (module=<module at remote 0x7ffff7198900>, args=0x555556d70650, nargs=1)
    at Python/clinic/bltinmodule.c.h:325
#17 0x00007ffff7b31940 in cfunction_vectorcall_FASTCALL (func=<built-in method eval of module object at remote 0x7ffff7198900>, 
    args=0x555556d70650, nargsf=9223372036854775809, kwnames=0x0) at Objects/methodobject.c:430
#18 0x00007ffff7be1ed7 in _PyObject_VectorcallTstate (tstate=0x555555577520, 
    callable=<built-in method eval of module object at remote 0x7ffff7198900>, args=0x555556d70650, nargsf=9223372036854775809, 
    kwnames=0x0) at ./Include/cpython/abstract.h:114
#19 0x00007ffff7be1f36 in PyObject_Vectorcall (callable=<built-in method eval of module object at remote 0x7ffff7198900>, 
    args=0x555556d70650, nargsf=9223372036854775809, kwnames=0x0) at ./Include/cpython/abstract.h:123
#20 0x00007ffff7bf4711 in call_function (tstate=0x555555577520, trace_info=0x7ffffffdbfc0, pp_stack=0x7ffffffdb430, oparg=1, 
    kwnames=0x0) at Python/ceval.c:5893
#21 0x00007ffff7befd34 in _PyEval_EvalFrameDefault (tstate=0x555555577520, 
    f=Frame 0x555556d70440, for file /tmp/portage/dev-python/trimesh-3.23.3/work/trimesh-3.23.3/tests/test_cache.py, line 251, in test_method_combinations (self=<CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_...(truncated), throwflag=0)
    at Python/ceval.c:4213
#22 0x00007ffff7be218a in _PyEval_EvalFrame (tstate=0x555555577520, 
    f=Frame 0x555556d70440, for file /tmp/portage/dev-python/trimesh-3.23.3/work/trimesh-3.23.3/tests/test_cache.py, line 251, in test_method_combinations (self=<CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_...(truncated), throwflag=0)
    at ./Include/internal/pycore_ceval.h:46
#23 0x00007ffff7bf29e7 in _PyEval_Vector (tstate=0x555555577520, con=0x7ff7ebd89b50, locals=0x0, args=0x7ff7eb8fa410, argcount=1, 
    kwnames=0x0) at Python/ceval.c:5067
#24 0x00007ffff7adddcb in _PyFunction_Vectorcall (func=<function at remote 0x7ff7ebd89b40>, stack=0x7ff7eb8fa410, nargsf=1, 
    kwnames=0x0) at Objects/call.c:342
#25 0x00007ffff7ae0878 in _PyObject_VectorcallTstate (tstate=0x555555577520, callable=<function at remote 0x7ff7ebd89b40>, 
    args=0x7ff7eb8fa410, nargsf=1, kwnames=0x0) at ./Include/cpython/abstract.h:114
#26 0x00007ffff7ae0b6c in method_vectorcall (method=<method at remote 0x7ff7ecf31080>, args=0x7ff7eb8fa418, 
    nargsf=9223372036854775808, kwnames=0x0) at Objects/classobject.c:53
#27 0x00007ffff7be1ed7 in _PyObject_VectorcallTstate (tstate=0x555555577520, callable=<method at remote 0x7ff7ecf31080>, 
    args=0x7ff7eb8fa418, nargsf=9223372036854775808, kwnames=0x0) at ./Include/cpython/abstract.h:114
#28 0x00007ffff7be1f36 in PyObject_Vectorcall (callable=<method at remote 0x7ff7ecf31080>, args=0x7ff7eb8fa418, 
    nargsf=9223372036854775808, kwnames=0x0) at ./Include/cpython/abstract.h:123
#29 0x00007ffff7bf4711 in call_function (tstate=0x555555577520, trace_info=0x7ffffffdd0f0, pp_stack=0x7ffffffdc560, oparg=0, 
    kwnames=0x0) at Python/ceval.c:5893
#30 0x00007ffff7befd34 in _PyEval_EvalFrameDefault (tstate=0x555555577520, 
    f=Frame 0x7ff7eb8fa2a0, for file /usr/lib/python3.10/unittest/case.py, line 549, in _callTestMethod (self=<CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_S...(truncated), throwflag=0)
    at Python/ceval.c:4213
#31 0x00007ffff7be218a in _PyEval_EvalFrame (tstate=0x555555577520, 
    f=Frame 0x7ff7eb8fa2a0, for file /usr/lib/python3.10/unittest/case.py, line 549, in _callTestMethod (self=<CacheTest(_testMethodName='test_method_combinations', _outcome=<_Outcome(expecting_failure=False, result=<TestCaseFunction(keywords=<NodeKeywords at remote 0x7ff7ebcd5040>, own_markers=[], extra_keyword_matches=set(), stash=<Stash at remote 0x7ff7ebf09b10>, _report_sections=[], user_properties=[], _obj=<method at remote 0x7ff7ecf31080>, originalname='test_method_combinations', _fixtureinfo=<FuncFixtureInfo at remote 0x7ff7ebccad80>, fixturenames=['_unittest_setUpClass_fixture_CacheTest', 'request'], funcargs={'_unittest_setUpClass_fixture_CacheTest': None, 'request': <FixtureRequest(_pyfuncitem=<...>, fixturename=None, _scope=<Scope(_value_='function', _name_='Function', __objclass__=<EnumMeta(_generate_next_value_=<function at remote 0x7ffff6fb00d0>, __module__='_pytest.scope', __annotations__={'Function': '_ScopeName', 'Class': '_ScopeName', 'Module': '_ScopeName', 'Package': '_ScopeName', 'Session': '_S...(truncated), throwflag=0)
    at ./Include/internal/pycore_ceval.h:46
#32 0x00007ffff7bf29e7 in _PyEval_Vector (tstate=0x555555577520, con=0x7ffff677bd10, locals=0x0, args=0x555556eae4e0, argcount=2, 
    kwnames=0x0) at Python/ceval.c:5067
#33 0x00007ffff7adddcb in _PyFunction_Vectorcall (func=<function at remote 0x7ffff677bd00>, stack=0x555556eae4e0, 
    nargsf=9223372036854775810, kwnames=0x0) at Objects/call.c:342
#34 0x00007ffff7be1ed7 in _PyObject_VectorcallTstate (tstate=0x555555577520, callable=<function at remote 0x7ffff677bd00>, 
    args=0x555556eae4e0, nargsf=9223372036854775810, kwnames=0x0) at ./Include/cpython/abstract.h:114
[…]
(gdb) up

#1  0x00007ffff5bb2b36 in NPY_cast_info_xfree (cast_info=0x7ffffffd9dc0)
    at ../numpy-1.26.0b1/numpy/core/src/multiarray/dtype_transfer.h:62
62          NPY_AUXDATA_FREE(cast_info->auxdata);
(gdb) p *cast_info->auxdata

$1 = {free = 0x0, clone = 0x0, reserved = {0x55555555b540, 0x7ff7eb8fa750}}

Runtime information:

3.10.12 (main, Aug 19 2023, 14:54:09) [GCC 13.2.0]
[{'numpy_version': '1.26.0b1',
  'python': '3.10.12 (main, Aug 19 2023, 14:54:09) [GCC 13.2.0]',
  'uname': uname_result(system='Linux', node='gentoo-amd64', release='6.4.7-gentoo-dist', version='#1 SMP PREEMPT_DYNAMIC Thu Jul 27 12:32:01 -00 2023', machine='x86_64')},
 {'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
                      'found': ['SSSE3',
                                'SSE41',
                                'POPCNT',
                                'SSE42',
                                'AVX',
                                'F16C',
                                'FMA3',
                                'AVX2'],
                      'not_found': ['AVX512F',
                                    'AVX512CD',
                                    'AVX512_KNL',
                                    'AVX512_KNM',
                                    'AVX512_SKX',
                                    'AVX512_CLX',
                                    'AVX512_CNL',
                                    'AVX512_ICL',
                                    'AVX512_SPR']}},
 {'architecture': 'ZEN',
  'filepath': '/usr/lib64/libopenblas_zenp-r0.3.23.so',
  'internal_api': 'openblas',
  'num_threads': 32,
  'prefix': 'libopenblas',
  'threading_layer': 'openmp',
  'user_api': 'blas',
  'version': '0.3.23'},
 {'filepath': '/usr/lib/gcc/x86_64-pc-linux-gnu/13/libgomp.so.1.0.0',
  'internal_api': 'openmp',
  'num_threads': 12,
  'prefix': 'libgomp',
  'user_api': 'openmp',
  'version': None}]

Context for the issue:

No response

@charris charris added this to the 1.26.0 release milestone Aug 19, 2023
@tylerjereddy
Copy link
Contributor

You can see choose in the debug output. I did a git bisect on NumPy with the provided reproducer, and one of the revisions to my PR fixing a refcount leak (gh-24188) comes up.

e4b880e494ee0a0125ed01ed61b5b2e24802fa48 is the first bad commit
commit e4b880e494ee0a0125ed01ed61b5b2e24802fa48
Author: Sebastian Berg <[email protected]>
Date:   Mon Jul 31 11:58:43 2023 +0200

    MAINT: Use explicit copy path in choose based on refcheck

 numpy/core/src/multiarray/item_selection.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

@tylerjereddy
Copy link
Contributor

NumPy-only segfault reproducer on latest main:

--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -10043,3 +10043,8 @@ def test_gh_22683():
     np.choose(np.zeros(10000, dtype=int), [a], out=a)
     refc_end = sys.getrefcount(b)
     assert refc_end - refc_start < 10
+
+
+def test_gh_24459():
+    a = np.zeros((50, 3), dtype=np.float64)
+    np.choose(a, [3, -1])

@tylerjereddy
Copy link
Contributor

Segfault goes away if a has type np.int64, and the choose docstring says:

This array must contain integers

At NumPy v1.25.2 the same reproducer results in error instead of segfault:

TypeError: Cannot cast array data from dtype('float64') to dtype('int64') according to the rule 'safe'

The full suite passes on main with:

--- a/numpy/core/src/multiarray/item_selection.c
+++ b/numpy/core/src/multiarray/item_selection.c
@@ -1119,7 +1119,6 @@ PyArray_Choose(PyArrayObject *ip, PyObject *op, PyArrayObject *out,
     return (PyObject *)obj;
 
  fail:
-    NPY_cast_info_xfree(&cast_info);
     Py_XDECREF(multi);
     for (i = 0; i < n; i++) {
         Py_XDECREF(mps[i]);
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 966b75cc1..2836c8985 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -10043,3 +10043,9 @@ def test_gh_22683():
     np.choose(np.zeros(10000, dtype=int), [a], out=a)
     refc_end = sys.getrefcount(b)
     assert refc_end - refc_start < 10
+
+
+def test_gh_24459():
+    a = np.zeros((50, 3), dtype=np.float64)
+    with pytest.raises(TypeError):
+        np.choose(a, [3, -1])

Anyway, that's probably enough info to give Sebastian or Nathan a solid clue. For the record, I think the trimesh test is using a try/except block to check for errors being raised or something.

@mikedh
Copy link

mikedh commented Aug 19, 2023

Oh yeah the trimesh cache fuzzing test has surfaced a number of bugs in numpy. By any chance is this bug also reproduced by my attempt to upstream that test in #24175 ?

@ngoldbaum
Copy link
Member

Thanks for the report @mgorny and test @tylerjereddy!

With a debug build of numpy, I get:

python: ../numpy/core/src/multiarray/dtype_transfer.h:61: NPY_cast_info_xfree: Assertion `cast_info->context.descriptors == cast_info->descriptors' failed.

Ah yes, the issue is that the NPY_Cast_Info struct is declared after the first goto fail, so the NPY_cast_info_xfree is given junk if goto fail is triggered before the struct is declared.

PR incoming...

@mgorny
Copy link
Contributor Author

mgorny commented Aug 22, 2023

Thanks a lot! I can confirm that I can no longer reproduce the crash with this patch applied.

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

Successfully merging a pull request may close this issue.

5 participants