You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Regression segfault under CPython 3.12a5 in the SymPy test suite #102250
I don't yet have a simpler reproducer for this because it seems to be non-deterministic but the SymPy test suite reliably invokes a segfault under 3.12 alpha 5 after about 5 minutes. The tests that are running at the time of the segfault will pass if run in isolation. Running the whole test suite though will cause it to fail randomly at one of a few specific places. I don't have a simpler reproducer because running a smaller part of the test suite does not reproduce the problem.
Error messages
Usually:
Segmentation fault: 11
In one case I have also seen (on OSX):
Bus error: 10
Your environment
CPython versions tested on: 3.12 alpha 5 (the problem is not seen with 3.11 or earlier).
Operating system and architecture: Ubuntu and OSX, both on x84-64 CPU.
The problem was seen initially in GitHub Actions CI on an Ubuntu 20.04 runner but I have also reproduced it locally in OSX (an Intel-CPU Macbook).
I don't immediately have a setup that I can use to bisect this but I will get one set up soon to narrow this down.
I got another crash from sympy but not sure it's CPython issue or Sympy issue at this moment.
(Buf AFAIK, sympy is pure-python code..)
sympy/core/tests/test_relational.py[64] ...............f.....................f..
...Modules/gcmodule.c:115: gc_decref: Assertion "gc_get_refs(g) > 0" failed: refcount is too small
Enable tracemalloc to get the memory block allocation traceback
object address : 0x1064b25e0
object refcount : 6
object type : 0x145c63630
object type name: floor
object repr : floor(x)
Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized
Current thread 0x000000010197c580 (most recent call first):
Garbage-collecting
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/facts.py", line 533 in <genexpr>
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/facts.py", line 533 in deduce_all_facts
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py", line 546 in _ask
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py", line 483 in getit
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/add.py", line 703 in _eval_is_zero
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py", line 539 in _ask
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/assumptions.py", line 483 in getit
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/relational.py", line 1561 in is_eq
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/relational.py", line 1555 in is_eq
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/relational.py", line 629 in __new__
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/core/tests/test_relational.py", line 967 in test_issue_10927
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py", line 1281 in test_file
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py", line 1146 in test
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py", line 568 in _test
File "/Users/user/oss/cpython/.venv/lib/python3.12/site-packages/sympy/testing/runtests.py", line 498 in test
File "<stdin>", line 1 in <module>
[1] 21140 abort python
I got another crash from sympy but not sure it's CPython issue or Sympy issue at this moment. (Buf AFAIK, sympy is pure-python code..)
The crash you showed suggests this is a segfault arising from a refcounting bug. Yes, SymPy is pure Python. It can be used with other optional dependencies that are not pure Python like numpy, gmpy2 etc but this bug is seen without any of those. A refcounting bug here is definitely a CPython bug.
do you have time to debug it to help us? Which test exacty fails? Or is it a combination / sequence of tests?
I am trying to bisect it currently but it's a slow process because of the time taken to build cpython and then run the sympy test suite. Also it is difficult because the failure itself is not completely deterministic. As I said in the OP running individual tests does not reproduce the failure so it is not possible to narrow it down to less than running the whole test suite.
Actually I have narrowed it down a little bit. It seems that the first 1/6 of the test suite is enough to reproduce this:
That does not reduce the time taken for the crash to show up but it does reduce the time taken to reproduce the crash not happening which is useful for bisecting.
I haven't quite finished bisecting but I'm currently down to this range:
commit df10571a130c46d67756239e76ad69a3d730a990 (refs/bisect/bad)
Author: Steve Dower <steve.dower@python.org>
Date: Mon Jan 16 16:05:39 2023 +0000
gh-100320: Fix path calculations on Windows when python.exe is moved outside of the normal location (GH-100947)
commit 7b14c2ef194b6eed79670aa9d7e29ab8e2256a56
Author: Mark Shannon <mark@hotpy.org>
Date: Mon Jan 16 12:35:21 2023 +0000
GH-100982: Add `COMPARE_AND_BRANCH` instruction (GH-100983)
commit b1a74a182d8762bda51838401ac92b6ebad9632a
Author: Nikita Sobolev <mail@sobolevn.me>
Date: Mon Jan 16 13:46:07 2023 +0300
gh-101056: Fix memory leak in `formatfloat()` in `bytesobject.c` (#101057)
commit b82049993f74185da71adf2eb8d6c8f15db063e1
Author: scrazzz <scruzism@mail.com>
Date: Mon Jan 16 13:44:50 2023 +0300
Docs: Remove duplicate `TraversableResources` reference (#101068)
commit 74c20b6ecee125e76c187c3f78c55f39501702ae (HEAD)
Author: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Date: Mon Jan 16 16:11:57 2023 +0530
GH-100997: fix refleak in `_testinternalcapi.c` (#101058)
commit 8e9d08b062bbabfe439bc73f82e3d7bb3800189e
Author: Oleg Iarygin <oleg@arhadthedev.net>
Date: Mon Jan 16 00:36:31 2023 +0400
gh-101041: Fix a misspelled name of `utctimetuple` in a doc warning (GH-101042)
commit 5e9df888dd5ab0e59d1cebc30c998a17aa65a3e2
Author: Cristián Maureira-Fredes <cmaureir@users.noreply.github.com>
Date: Sun Jan 15 16:12:37 2023 +0100
Fix `ctypes` typo in `set_exception` (#101040)
commit f6307d44167e9c110a1db442f7a33deb365e89a8 (refs/bisect/good-f6307d44167e9c110a1db442f7a33deb365e89a8)
Author: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Date: Sun Jan 15 20:39:26 2023 +0530
GH-100892: consolidate `HEAD_LOCK/HEAD_UNLOCK` macros (#100953)
However, running sympy/diffgeom/tests/test_function_diffgeom_book.py repeatedly (100 times) doesn't seem to reproduce the segfault - likewise for sympy/functions/special/tests/test_error_functions.py.
I will do a bit more testing with the parent commit (b1a74a1) to confirm that the bug is not seen there.
I confirm the full test suite passes with the parent commit so I'm confident that the problem begines with 7b14c2e.
Does running the sympy/functions/special/tests/test_error_functions.py test repeatedly by itself cause the segfault?
I tried something similar to this. Exactly where it crashes is different on different runs but for example it sometimes crashes in the diffgeom tests so I made a script to run just the diffgeom tests 100 times and that didn't give any crash. I'll try again with:
importsympyforninrange(1000):
print()
print('-------------------------------------- n =', n)
print()
sympy.test('test_error_functions', subprocess=False)
It's possible that it would be different by setting the environment variable SYMPY_USE_CACHE=no although that makes everything much slower.
from sympy.core.symbol import symbols
x = symbols('x')
assert x > 0
Okay this starts to make sense. A comparison like x > 0 will call x.__gt__(0) which would usually be expected to return a bool. However Symbol.__gt__ instead returns a symbolic GreaterThan(x, 0) object to represent the inequality symbolically:
>>>cond=x>0>>>condx>0>>>type(cond)
<class'sympy.core.relational.StrictGreaterThan'>>>>bool(cond) # it isn't known if cond is True or FalseTraceback (mostrecentcalllast):
File"<stdin>", line1, in<module>File"/home/oscar/current/sympy/sympy.git/sympy/core/relational.py", line510, in__bool__raiseTypeError("cannot determine truth value of Relational")
TypeError: cannotdeterminetruthvalueofRelational
The COMPARE_AND_BRANCH opcode evaluates this here:
I also would like to say thanks to all involved with the faster-CPython project. I know that any significant changes will cause churn and some bugs like this one but SymPy and many other projects stand to benefit significantly from the speed improvements in CPython.
Now that 3.12 tests pass I have collected the total time taken (in CI) to run the SymPy test and doctest suite under different CPython versions:
(That's the time for tests1+tests2+doctests in the linked CI job. There "latest" means 3.11.)
According to those timings 3.12 looks like showing the biggest effect from recent releases and the cumulative effect from 3.8 to 3.12 is a 30% reduction in runtime.
Activity
sobolevn commentedon Feb 26, 2023
@oscarbenjamin do you have time to debug it to help us? Which test exacty fails? Or is it a combination / sequence of tests?
corona10 commentedon Feb 26, 2023
I got another crash from sympy but not sure it's CPython issue or Sympy issue at this moment.
(Buf AFAIK, sympy is pure-python code..)
OTheDev commentedon Feb 26, 2023
main(sympy.__version__ == '1.11.1'):Second run
Not on
3.11.2(Feb 8 Gzipped source tarball,sympy.__version__ == '1.11.1') though:Moreover
It looks like if CPython is the culprit, it probably should be bisectable in 3.12. Unfortunately, the test suite is quite long! :)
oscarbenjamin commentedon Feb 26, 2023
The crash you showed suggests this is a segfault arising from a refcounting bug. Yes, SymPy is pure Python. It can be used with other optional dependencies that are not pure Python like numpy, gmpy2 etc but this bug is seen without any of those. A refcounting bug here is definitely a CPython bug.
oscarbenjamin commentedon Feb 26, 2023
I am trying to bisect it currently but it's a slow process because of the time taken to build cpython and then run the sympy test suite. Also it is difficult because the failure itself is not completely deterministic. As I said in the OP running individual tests does not reproduce the failure so it is not possible to narrow it down to less than running the whole test suite.
Actually I have narrowed it down a little bit. It seems that the first 1/6 of the test suite is enough to reproduce this:
That does not reduce the time taken for the crash to show up but it does reduce the time taken to reproduce the crash not happening which is useful for bisecting.
I haven't quite finished bisecting but I'm currently down to this range:
OTheDev commentedon Feb 26, 2023
Tests pass in
3.12.0a4(Head 3d5d3f7, Jan 10)oscarbenjamin commentedon Feb 26, 2023
Bisect complete:
That's 7b14c2e from gh-100983.
I will do a bit more testing with the parent commit (b1a74a1) to confirm that the bug is not seen there.
CC @markshannon
OTheDev commentedon Feb 26, 2023
Full test suite green for me in b1a74a1.
markshannon commentedon Feb 26, 2023
Does running the
sympy/functions/special/tests/test_error_functions.pytest repeatedly by itself cause the segfault?OTheDev commentedon Feb 26, 2023
Attempting to run the full test suite at 7b14c2e, I encounter a segfault at
However, running
sympy/diffgeom/tests/test_function_diffgeom_book.pyrepeatedly (100 times) doesn't seem to reproduce the segfault - likewise forsympy/functions/special/tests/test_error_functions.py.oscarbenjamin commentedon Feb 26, 2023
I confirm the full test suite passes with the parent commit so I'm confident that the problem begines with 7b14c2e.
I tried something similar to this. Exactly where it crashes is different on different runs but for example it sometimes crashes in the diffgeom tests so I made a script to run just the diffgeom tests 100 times and that didn't give any crash. I'll try again with:
It's possible that it would be different by setting the environment variable
SYMPY_USE_CACHE=noalthough that makes everything much slower.How many repetitions should I expect to need?
dtrodrigues commentedon Feb 26, 2023
The crash @corona10 mentioned is reproducible with
--with-pydebugenabled. A simpler reproducer isThe bytecode for both is below
b1a74a1 (good):
7b14c2e (bad):
with the difference between the two being
COMPARE_OPvsCOMPARE_AND_BRANCH.I can't cause this alone to cause a segfault when
--with-pydebugis not enabled.Edit: Removing https://github.com/sympy/sympy/blob/sympy-1.11.1/sympy/core/tests/test_relational.py#L860-L869 from the sympy test suite allow sthe subset of the test suite which I was running on (split='1/12') to run without segfaulting anymore. Adding the test back in reintroduces the segfault that appears later on.
oscarbenjamin commentedon Feb 26, 2023
Okay this starts to make sense. A comparison like
x > 0will callx.__gt__(0)which would usually be expected to return abool. HoweverSymbol.__gt__instead returns a symbolicGreaterThan(x, 0)object to represent the inequality symbolically:The
COMPARE_AND_BRANCHopcode evaluates this here:cpython/Python/bytecodes.c
Lines 1854 to 1857 in 7b14c2e
Now I think:
PyObject_RichComparewill raise an exception so it returnsNULL.Py_DECREF(left)decrefs the Symbol objectx.cond == NULLevaluates as true so we do theERROR_IF.I'm not sure what
ERROR_IFdoes:cpython/Python/bytecodes.c
Line 68 in 7b14c2e
I guess it means
goto error;. I'm not sure what happens then.oscarbenjamin commentedon Feb 26, 2023
To be clear it is the Symbol object refcount that causes the crash. Using
--with-pydebugand the short repro above:oscarbenjamin commentedon Feb 26, 2023
No it won't. It will return the
GreaterThan:cpython/Python/bytecodes.c
Lines 1854 to 1869 in 7b14c2e
Then
PyObject_IsTruereturns-1becauseGreaterThan.__bool__raises. Then we hit theerr < 0andgoto error;.oscarbenjamin commentedon Feb 26, 2023
Before 7b14c2e the
COMPARE_OPcode did not callPyObject_IsTrue:cpython/Python/bytecodes.c
Lines 1839 to 1854 in b1a74a1
oscarbenjamin commentedon Feb 26, 2023
Here is a simple reproducer not involving SymPy:
With
--with-pydebugthis crashes:oscarbenjamin commentedon Feb 26, 2023
In fact it crashes with an ordinary build as well including the OSX 3.12a5 build that I installed from python.org.
gh-102250: Fix double-decref in COMPARE_AND_BRANCH error case (GH-102287
AlexWaygood commentedon Feb 27, 2023
Fixed in #102287 by @sweeneyde. Thanks for reporting @oscarbenjamin!
oscarbenjamin commentedon Feb 27, 2023
Thanks for fixing and thanks everyone for the help pinning this down!
Merge branch 'main' into inlinecomp2
oscarbenjamin commentedon Mar 9, 2023
Thanks again to all.
The 3.12a6 release rolled out to SymPy CI which is now all green for CPython 3.12 (although not the latest mypy release...):
https://github.com/sympy/sympy/actions/runs/4367781443
I also would like to say thanks to all involved with the faster-CPython project. I know that any significant changes will cause churn and some bugs like this one but SymPy and many other projects stand to benefit significantly from the speed improvements in CPython.
Now that 3.12 tests pass I have collected the total time taken (in CI) to run the SymPy test and doctest suite under different CPython versions:
3.8: 3439 secs
3.9: 2914 secs
3.10: 3132 secs
3.11: 3009 secs
3.12a6: 2503 secs
(That's the time for tests1+tests2+doctests in the linked CI job. There "latest" means 3.11.)
According to those timings 3.12 looks like showing the biggest effect from recent releases and the cumulative effect from 3.8 to 3.12 is a 30% reduction in runtime.