Skip to content

gh-152254: Fix a crash in PyObject_ClearManagedDict under memory pressure - #152255

Open
sobolevn wants to merge 3 commits into
python:mainfrom
sobolevn:issue-152254
Open

sobolevn wants to merge 3 commits into
python:mainfrom
sobolevn:issue-152254

Conversation

@sobolevn

@sobolevn sobolevn commented Jun 26, 2026 •

Copy link
Copy Markdown
Member

@sobolevn

sobolevn commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

@vstinner can you please take a look? :)

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

This PR is stale because it has been open for 90 days with no activity.

@github-actions github-actions Bot added the stale Stale PR or inactive for long period of time. label Oct 5, 2026

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to write a test to test this code path? See with support.inject_memory_error_cm():.

@sobolevn sobolevn removed the stale Stale PR or inactive for long period of time. label Oct 5, 2026
@sobolevn

Copy link
Copy Markdown
Member Author

I think that it would be rather hard to do :(

So, instead I added PyObject_ClearManagedDict C-API tests, including a new reproducer.

Before:

test_object_clear_managed_dict_ft_memory_error (test.test_capi.test_object.CAPITest.test_object_clear_managed_dict_ft_memory_error) ... Assertion failed: (_Py_IsOwnedByCurrentThread((PyObject *)mp) || IS_DICT_SHARED(mp)), function set_keys, file dictobject.c, line 207.
Fatal Python error: Aborted

<Cannot show all threads while the GIL is disabled>
Stack (most recent call first):
  File "/Users/sobolev/Desktop/cpython/Lib/test/test_capi/test_object.py", line 420 in worker
  File "/Users/sobolev/Desktop/cpython/Lib/test/support/threading_helper.py", line 279 in wrapper_func
  File "/Users/sobolev/Desktop/cpython/Lib/threading.py", line 1161 in run
  File "/Users/sobolev/Desktop/cpython/Lib/threading.py", line 1219 in _bootstrap_inner
  File "/Users/sobolev/Desktop/cpython/Lib/threading.py", line 1181 in _bootstrap

Current thread's C stack trace (most recent call first):
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _Py_DumpStack+0x44 [0x104538fe4]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at faulthandler_dump_c_stack+0x68 [0x10456b8f0]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at faulthandler_fatal_error+0x1ac [0x10456b68c]
  Binary file "/usr/lib/system/libsystem_platform.dylib", at _sigtramp+0x38 [0x18c9656a4]
  Binary file "/usr/lib/system/libsystem_pthread.dylib", at pthread_kill+0x128 [0x18c92b88c]
  Binary file "/usr/lib/system/libsystem_c.dylib", at abort+0x7c [0x18c834a3c]
  Binary file "/usr/lib/system/libsystem_c.dylib", at err+0x0 [0x18c833c70]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at set_keys+0x70 [0x10427eca0]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at PyObject_ClearManagedDict+0x144 [0x10427e834]
  Binary file "/Users/sobolev/Desktop/cpython/Modules/_testcapi.cpython-316td-darwin.so", at pyobject_clear_managed_dict+0x1c [0x1050dc7dc]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at cfunction_vectorcall_O+0x10c [0x10429c050]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyVectorcall_Call+0xf0 [0x1041ee778]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_Call+0x130 [0x1041ee9d4]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at PyObject_Call+0x34 [0x1041eeaac]
  Binary file "/Users/sobolev/Desktop/cpython/Modules/_testcapi.cpython-316td-darwin.so", at call_with_nomemory+0x1d4 [0x1050beb14]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at cfunction_call+0x194 [0x10429cbb8]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_MakeTpCall+0x284 [0x1041edc00]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_VectorcallTstate+0x11c [0x1041ed610]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at PyObject_Vectorcall+0x3c [0x1041ee898]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _Py_VectorCallInstrumentation_StackRefSteal+0xc8 [0x1043f7984]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyEval_EvalFrameDefault+0x665c [0x1043ff544]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyEval_EvalFrame+0x3c [0x1043f742c]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyEval_Vector+0x1a4 [0x1043f7378]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyFunction_Vectorcall+0x13c [0x1041eecf8]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_VectorcallTstate+0x13c [0x1041ed630]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_VectorcallPrepend+0x1b4 [0x1041efd54]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at method_vectorcall+0x9c [0x1041f30c0]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_VectorcallTstate+0x13c [0x104468460]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at context_run+0x98 [0x1044680ec]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at method_vectorcall_FASTCALL_KEYWORDS+0x9c [0x10420a67c]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at _PyObject_VectorcallTstate+0x13c [0x1041ed630]
  Binary file "/Users/sobolev/Desktop/cpython/python.exe", at PyObject_Vectorcall+0x3c [0x1041ee898]
  <truncated rest of calls>

Extension modules: _testcapi, _testinternalcapi (total: 2)
[1]    6935 abort      ./python.exe -m test -v test_capi.test_object

After: all tests pass 🎉

@sobolevn sobolevn added needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes labels Nov 14, 2026

def test_object_clear_managed_dict(self):
# PyObject_ClearManagedDict
clear = _testcapi.pyobject_clear_managed_dict

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I would prefer to call it clear_managed_dict, since clear() sounds like a different function (like PyDict_Clear()). Same remark in the second test.

Comment thread Lib/test/test_capi/test_object.py Resolved

@threading_helper.requires_working_threading()
def test_object_clear_managed_dict_ft_memory_error(self):
# PyObject_ClearManagedDict, gh-152254

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a short sentence to describe the purpose of the test? I understand that you call PyObject_ClearManagedDict() from a different thread so _Py_IsOwnedByCurrentThread() is false.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants