Repository navigation
test_repl's test_no_memory: AssertionError: -6 not found in (1, 120) #118331
Copy link
Copy link
Closed
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Bug report
Bug description:
One of my PRs (#118283) started failing (https://github.com/python/cpython/actions/runs/8843882336?pr=118283) with this. Investigating, I can reproduce it locally on main, although I don't know why the CI passes on main.
OS: macOS Sonoma 14.4.1, M2.
To reproduce
git clone https://github.com/python/cpython
cd cpython
./configure --with-pydebug && make -j10
./python.exe Lib/test/test_repl.pyActual result
.....F.
======================================================================
FAIL: test_no_memory (__main__.TestInteractiveInterpreter.test_no_memory)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/private/tmp/cpython/Lib/test/test_repl.py", line 86, in test_no_memory
self.assertIn(p.returncode, (1, 120))
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: -6 not found in (1, 120)Printing output from the test:
Python 3.13.0a5+ (bisect/good-e16062dd3428a5846344e0a8c6ee2f352d34ce1b-1-gdf73179048:df73179048, A) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> >>> >>> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
1/0
~^~
ZeroDivisionError: division by zero
>>> After the exception.
>>> object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b9a0
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x102f8b930
object refcount : 3
object type : 0x102b831a8
object type name: MemoryError
object repr :
lost sys.stderr
Fatal Python error: _Py_Dealloc: Deallocator of type '_thread._localdummy' raised an exception
Python runtime state: finalizing (tstate=0x0000000102bf3c40)
Current thread 0x0000000201f77ac0 (most recent call first):
<no Python frame>
Expected result
It passes with v3.13.0a5, where output is:
Python 3.13.0a5 (tags/v3.13.0a5:076d169ebb, Apr 26 2024, 22:13:38) [Clang 15.0.0 (clang-1500.3.9.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> >>> >>> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
1/0
~^~
ZeroDivisionError: division by zero
>>> After the exception.
>>> object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f63a10
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
object address : 0x100f639a0
object refcount : 3
object type : 0x100b5f1a8
object type name: MemoryError
object repr :
lost sys.stderr
The main difference is the failure includes this:
Fatal Python error: _Py_Dealloc: Deallocator of type '_thread._localdummy' raised an exception
Python runtime state: finalizing (tstate=0x0000000102bf3c40)
Current thread 0x0000000201f77ac0 (most recent call first):
<no Python frame>
Bisecting
df7317904849a41d51db39d92c5d431a18e22637 is the first bad commit
commit df7317904849a41d51db39d92c5d431a18e22637
Author: mpage <mpage@meta.com>
Date: Mon Apr 8 07:58:38 2024 -0700
gh-111926: Make weakrefs thread-safe in free-threaded builds (#117168)
Most mutable data is protected by a striped lock that is keyed on the
referenced object's address. The weakref's hash is protected using the
weakref's per-object lock.
Note that this only affects free-threaded builds. Apart from some minor
refactoring, the added code is all either gated by `ifdef`s or is a no-op
(e.g. `Py_BEGIN_CRITICAL_SECTION`).
Include/cpython/weakrefobject.h | 8 +
Include/internal/pycore_interp.h | 7 +
Include/internal/pycore_object.h | 40 +-
Include/internal/pycore_pyatomic_ft_wrappers.h | 5 +
Include/internal/pycore_weakref.h | 73 +++-
Lib/test/test_sys.py | 8 +-
Lib/test/test_weakref.py | 19 +
Modules/_sqlite/blob.c | 5 +-
Modules/_sqlite/connection.c | 4 +-
Modules/_ssl.c | 13 +-
Modules/_ssl/debughelpers.c | 6 +-
Modules/_weakref.c | 42 +-
Modules/clinic/_weakref.c.h | 20 +-
Objects/dictobject.c | 8 +-
Objects/typeobject.c | 12 +-
Objects/weakrefobject.c | 537 ++++++++++++++-----------
Python/pystate.c | 9 +
17 files changed, 490 insertions(+), 326 deletions(-)
bisect found first bad commit
The PR was merged three weeks ago and the CI is passing.
On my PR (https://github.com/python/cpython/actions/runs/8843882336?pr=118283), free-threaded builds pass, but regular ones fail. Ubuntu and macOS fail with:
AssertionError: -6 not found in (1, 120)Windows with:
AssertionError: 3221225477 not found in (1, 120)3221225477 seems to be 0xc0000005 STATUS_ACCESS_VIOLATION.
CPython versions tested on:
3.13
Operating systems tested on:
macOS
Linked PRs
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Activity
colesbury commentedon Apr 26, 2024
I am able to reproduce it locally when checking out #118283 (but not in main for whatever reason).
The bug I saw was due to
_PyObject_SetManagedDictcalling_PyDict_DetachFromObject, which sets an exception (due to the no-memory condition). The exception is not handled, which causes the fatal error in_Py_Dealloc.We should call
PyErr_WriteUnraisable()or further propagate up the error.cc @DinoV (I think the relevant PR is #114742)
pythongh-118331: Handle errors in _PyObject_SetManagedDict
Merge branch 'pythongh-118331-unraisable' into doctest-refactor-color…
mpage commentedon Apr 27, 2024
@hugovk - I still can't repro this after merging gh-118334, but I did take a look through the weakref code and found a preexisting bug that might be what you're hitting. Can you try merging gh-118338 along with gh-118334 and see if it fixes things?
hugovk commentedon Apr 27, 2024
Good news!
Thanks both!
Merge branch 'main' into pythongh-118331-wr-no-mem
gh-118331: Don't raise an error if tuple allocation fails when cleari…
gh-118331: Handle errors in _PyObject_SetManagedDict (#118334)
colesbury commentedon Apr 29, 2024
@hugovk, both PRs are now merged. When you get a chance to merge
maininto your PR, would you please verify that everything is okay and close the issue?hugovk commentedon Apr 29, 2024
Passing now, thank you!
After the first run, 5 tests failed on "Windows (free-threading) / build and test (x86)" but passed when restarted.
https://github.com/python/cpython/actions/runs/8884999534/attempts/1
https://github.com/python/cpython/actions/runs/8884999534/job/24396359883
ZeroIntensity commentedon Feb 23, 2025
It looks like this wasn't fully fixed, I'm seeing failures on my PR: #130469
The test case seems to pass on main, but my PR triggers the failure again for whatever reason. On main, actually running the snippet from the test in the REPL results in an assertion failure, and a hang on 3.13 release builds:
mpage commentedon Feb 23, 2025
I think there are three separate issues on main that are being tickled. I haven't had a chance to investigate 3.13.
_PyList_FromStackRefStealOnSuccessis marked as non-escaping. A quick workaround here is to remove it from the non-escaping list.take_ownershipdoes not save and restore exceptions around the call to_PyFrame_GetFrameObject(). We should do that.list_deallocdoes not setob_itemtoNULLafter freeing the items array (only affects the free-threaded build). We should also do that.1.
_PyList_FromStackRefStealOnSuccessFirst, I think the assertion failure that @ZeroIntensity reported on the default build is because
_PyList_FromStackRefStealOnSuccessis marked as non-escaping. We are attempting to allocate a new list (frame 7)Allocating the list object succeeds because it is handled by the free list. Allocating the items array fails, and we decref the the list object that was returned from the free list:
cpython/Objects/listobject.c
Lines 259 to 263 in 1e4a434
The decref destroys the last reference, calls
_Py_Dealloc, and we end up hitting the assertion:cpython/Objects/object.c
Lines 2970 to 2972 in 1e4a434
Since
_PyList_FromStackRefStealOnSuccessis marked as non-escaping, the interpreter generator doesn't generate any code to set and clear the stack pointer around the call:cpython/Python/generated_cases.c.h
Lines 1017 to 1019 in 1e4a434
I'm not sure what the right solution is. I think
_PyList_FromStackRefStealOnSuccessis correctly marked as non-escaping because the decref can't execute arbitrary code and it's the only decref that can be performed. Removing it from the list of non-escaping calls gets us past the assertion and probably isn't too bad for performance. I suspect that there are probably other functions that are marked as non-escaping with similar properties as_PyList_FromStackRefStealOnSuccessunder low memory scenarios though and it doesn't seem great to have to pessimize those as well.2.
take_ownershipAfter working around the above, we hit another assertion that I believe is caused by unconditionally clearing
MemoryErrors intake_ownership.We're triggering this assertion:
cpython/Python/generated_cases.c.h
Lines 11987 to 11989 in 1e4a434
because no exception is set:
Running backwards, we can see that the exception is cleared in
take_ownership:take_ownershipclears anyMemoryErrorexceptions when getting the previous frame fails (even if they were not raised by the call to_PyFrame_GetFrameObject):cpython/Python/frame.c
Lines 74 to 79 in 1e4a434
In this case, there was a pre-existing
MemoryError(caused by failing to allocate the list) that shouldn't be cleared. I think we should save and restore the exception around the call to_PyFrame_GetFrameObject(prev);. Something like:After this, it looks like things are working again on the default build:
3.
list_deallocIt looks like there's another issue in the free-threaded build that we hit:
Again, we're attempting to allocate a new list. Allocating the list object succeeds because it's returned from the free list, but allocating the items array fails:
cpython/Objects/listobject.c
Lines 250 to 255 in 1e4a434
Since we hold the only reference, the decref ends up calling
list_dealloc, which is attempting to decref items in the items array, which has been filled with poisoned values since it was already freed:cpython/Objects/listobject.c
Lines 526 to 536 in 1e4a434
I think setting setting
ob_itemtoNULLafter we free the items array should fix the problem. Something like:After this, the free-threaded build no longer crashes:
Merge branch 'main' into pythongh-118331-nullify-items
gh-118331: Fix a couple of issues when list allocation fails (#130811)
gh-118331: Fix `test_list.ListTest.test_no_memory` under trace refs b…
ZeroIntensity commentedon Jun 19, 2025
This seems to be fixed now: