Skip to content

BUG: Segfault When __array_ufunc__ Called With Garbage #24023

Closed

Description

@mikedh

Describe the issue:

Thanks for the great work!

To try to detect bugs in a system which caches off numpy arrays, I have a test which calls every method returned by dir on a numpy array with many permutations of random data of various types. In the last few days CI has started segfaulting and I have been able to reproduce locally after upgrading to numpy=1.25.0 when calling array.__array_ufunc__(2.3, 1).

Admittedly calling every function with every permutation of random garbage data isn't real use case and happy to close this and just skip the __array_ufunc__ in this test (after which my test went back to passing). But it just started happening, reproduced pretty well and none of the other methods segfault under any inputs I could put together so I thought it might be interesting.

Reproduce the code example:

mikedh@luna:tests$ python -X faulthandler

Python 3.11.0rc1 (main, Aug 12 2022, 10:02:14) [GCC 11.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np

>>> a = np.empty(1)

>>> a.__array_ufunc__(2.3, 1)
Fatal Python error: Segmentation fault

Current thread 0x00007efca4ce1000 (most recent call first):
  File "<stdin>", line 1 in <module>

Extension modules: numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator (total: 13)
Segmentation fault (core dumped)

Error message:

Fatal Python error: Segmentation fault

Current thread 0x00007efca4ce1000 (most recent call first):
  File "<stdin>", line 1 in <module>

Extension modules: numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator (total: 13)
Segmentation fault (core dumped)

Runtime information:

I have seen this in Github actions, Docker, and my Parallels desktop Ubuntu 22.04 virtual.

My desktop VM:

In [7]: import sys, numpy; print(numpy.__version__); print(sys.version)
1.25.0
3.11.0rc1 (main, Aug 12 2022, 10:02:14) [GCC 11.2.0]

In [8]: print(numpy.show_runtime())
WARNING: `threadpoolctl` not found in system! Install it by `pip install threadpoolctl`. Once installed, try `np.show_runtime` again for more detailed build information
[{'numpy_version': '1.25.0',
  'python': '3.11.0rc1 (main, Aug 12 2022, 10:02:14) [GCC 11.2.0]',
  'uname': uname_result(system='Linux', node='luna', release='5.19.0-45-generic', version='#46~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 7 15:06:04 UTC 20', 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']}}]
None

Context for the issue:

It doesn't effect my work, I already skipped this in tests, I thought the team might find inducable hard segfaults interesting.

Here is the "call every method with garbage" test that induced the segfault

Activity

  1. added this to the 1.25.1 release milestone on Jun 23, 2023
  2. mikedh commented on Jun 23, 2023

    @mikedh
    Author

    There was one more segfault which didn't reproduce at all locally, but on every Github Actions run with ubuntu-latest the following produced a segfault:

    python -c "import numpy; a = numpy.random.random((100, 3)); a.astype()"
    

    When trying to reproduce either locally, or locally in docker I get the expected TypeError: astype() missing required argument 'dtype' (pos 0) but for some reason on the Github actions runners it segfaults. I would have thought it would reproduce with this but I couldn't get it to happen locally even on a bunch of base images:

    docker run -t python:3.11-slim-bullseye bash -c "pip install numpy && python -c 'import numpy; a = numpy.random.random((100, 3)); print(a.astype())'"
    

    I'm skipping astype and __array_ufunc__ and it's passing locally and in CI.

  3. seberg commented on Jun 23, 2023

    @seberg
    Member

    Thanks! I am not too worried about it since its not really user-facing, but the __array_ufunc__ should be easy to track down and fix. The astype() is also a real bug, but harder to find because its uninitialized stack values.

  4. ngoldbaum commented on Jun 23, 2023

    @ngoldbaum
    Member

    In my debug build of python:

    python -c "import numpy; a = numpy.random.random((100, 3)); a.astype()"
    /home/nathan/.pyenv/versions/3.10.9-debug/include/python3.10d/object.h:567: _Py_NegativeRefcount: Assertion failed: object has negative ref count
    <object at 0x55e66d4bc500 is freed>
    Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
    Python runtime state: initialized
    TypeError: astype() missing required argument 'dtype' (pos 0)
    
    Current thread 0x00007f2110dc4b80 (most recent call first):
      File "<string>", line 1 in <module>
    
    Extension modules: numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator (total: 13)
    [1]    309296 IOT instruction (core dumped)  python -c "import numpy; a = numpy.random.random((100, 3)); a.astype()"
    

    So there's probably a reference counting error in an error path somewhere.

  5. ngoldbaum commented on Jun 23, 2023

    @ngoldbaum
    Member

    And it's in code I wrote 🙃. I'll have a patch shortly.

  6. seberg commented on Jun 23, 2023

    @seberg
    Member

    I think might have been me, my think the initialization is just missing for the things we have been working on. I suspect the other issue is just not accounting for kwargs being NULL.

  7. ngoldbaum commented on Jun 23, 2023

    @ngoldbaum
    Member

    Here is the "call every method with garbage" test that induced the segfault

    Adding such a test to the numpy test suite seems worthwhile. Error paths have poor coverage in numpy's tests and this would make the tests hit more of them.

  8. ngoldbaum commented on Jun 23, 2023

    @ngoldbaum
    Member

    I suspect the other issue is just not accounting for kwargs being NULL.

    Yup:

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff7b884fc in PyDict_GetItemWithError (op=0x0, key='where') at Objects/dictobject.c:1513
    1513	Objects/dictobject.c: No such file or directory.
    (gdb) up
    #1  0x00007ffff6649c0d in any_array_ufunc_overrides (args=(), kwds=0x0)
        at ../../numpy/core/src/multiarray/methods.c:1151
    1151	    where_obj = PyDict_GetItemWithError(kwds, npy_ma_str_where);
    (gdb) p kwds
    $1 = 0x0
    

    I'll leave that one to you since I'm not familiar with the __array_ufunc__ internals.

  9. mikedh commented on Jul 13, 2023

    @mikedh
    Author

    Awesome thanks for the quick fixes!! __array_ufunc__ and astype are now passing for me on the 1.25.1 release, and I PR'd the fuzzing test in #24175 if the project thinks it'd be useful happy to contribute.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions