Skip to content
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

Addition to Issue#117783 #118408

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion Lib/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,17 @@ def f(): pass
return f

def create_bound_method():
return C().method
obj = C()
method = obj.method
try:
# Attempt to call the method through a bound method reference
result = method()
return result
except ReferenceError:
print("The object the method was bound to has been garbage collected.")
except Exception as e:
print(f"An error occurred: {e}")
return None


class Object:
Expand Down Expand Up @@ -1038,6 +1048,35 @@ def callback(obj):
stderr = res.err.decode("ascii", "backslashreplace")
self.assertNotRegex(stderr, "_Py_Dealloc: Deallocator of type 'TestObj'")

@support.cpython_only
def test_no_memory_when_clearing(self):
# gh-118331: Make sure we do not raise an exception from the destructor
# when clearing weakrefs if allocating the intermediate tuple fails.
code = textwrap.dedent("""
import _testcapi
import weakref

class TestObj:
pass

def callback(obj):
pass

obj = TestObj()
# The choice of 50 is arbitrary, but must be large enough to ensure
# the allocation won't be serviced by the free list.
try:
wrs = [weakref.ref(obj, callback) for _ in range(50)]
_testcapi.set_nomemory(0) # Force memory allocation to fail
except MemoryError:
print('MemoryError handled properly')
del obj
""").strip()
res, _ = script_helper.run_python_until_end("-c", code)
stderr = res.err.decode("ascii", "backslashreplace")
self.assertNotRegex(stderr, "_Py_Dealloc: Deallocator of type 'TestObj'")
self.assertIn('MemoryError handled properly', stderr)


class SubclassableWeakrefTestCase(TestBase):

Expand Down
2 changes: 2 additions & 0 deletions Objects/weakrefobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1019,8 +1019,10 @@ PyObject_ClearWeakRefs(PyObject *object)
_PyWeakref_ClearWeakRefsExceptCallbacks(object);
PyErr_WriteUnraisable(NULL);
PyErr_SetRaisedException(exc);
Py_XDECREF(exc); // Clean up the reference to the exception object
return;
}
Py_XDECREF(exc); // Clean up the reference if tuple creation is successful

Py_ssize_t num_items = 0;
for (int done = 0; !done;) {
Expand Down