mirror of
https://github.com/python/cpython.git
synced 2025-10-17 04:08:28 +00:00
Allocating a new weakref object can cause existing weakref objects for
the same object to be collected by the cyclic GC support if they are only referenced by a cycle. If the weakref being collected was one of the weakrefs without callbacks, some local variables for the constructor became invalid and have to be re-computed. The test caused a segfault under a debug build without the fix applied.
This commit is contained in:
parent
21ae4f983e
commit
bc875f5a36
2 changed files with 48 additions and 3 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import gc
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
import UserList
|
import UserList
|
||||||
|
@ -591,6 +592,37 @@ class ReferencesTestCase(TestBase):
|
||||||
gc.collect()
|
gc.collect()
|
||||||
self.assertEqual(alist, [])
|
self.assertEqual(alist, [])
|
||||||
|
|
||||||
|
def test_gc_during_ref_creation(self):
|
||||||
|
self.check_gc_during_creation(weakref.ref)
|
||||||
|
|
||||||
|
def test_gc_during_proxy_creation(self):
|
||||||
|
self.check_gc_during_creation(weakref.proxy)
|
||||||
|
|
||||||
|
def check_gc_during_creation(self, makeref):
|
||||||
|
thresholds = gc.get_threshold()
|
||||||
|
gc.set_threshold(1, 1, 1)
|
||||||
|
gc.collect()
|
||||||
|
class A:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def callback(*args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
referenced = A()
|
||||||
|
|
||||||
|
a = A()
|
||||||
|
a.a = a
|
||||||
|
a.wr = makeref(referenced)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# now make sure the object and the ref get labeled as
|
||||||
|
# cyclic trash:
|
||||||
|
a = A()
|
||||||
|
a.wrc = weakref.ref(referenced, callback)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
gc.set_threshold(*thresholds)
|
||||||
|
|
||||||
class Object:
|
class Object:
|
||||||
def __init__(self, arg):
|
def __init__(self, arg):
|
||||||
self.arg = arg
|
self.arg = arg
|
||||||
|
|
|
@ -630,16 +630,23 @@ PyWeakref_NewRef(PyObject *ob, PyObject *callback)
|
||||||
/* return existing weak reference if it exists */
|
/* return existing weak reference if it exists */
|
||||||
result = ref;
|
result = ref;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
Py_XINCREF(result);
|
Py_INCREF(result);
|
||||||
else {
|
else {
|
||||||
|
/* Note: new_weakref() can trigger cyclic GC, so the weakref
|
||||||
|
list on ob can be mutated. This means that the ref and
|
||||||
|
proxy pointers we got back earlier may have been collected,
|
||||||
|
so we need to compute these values again before we use
|
||||||
|
them. */
|
||||||
result = new_weakref(ob, callback);
|
result = new_weakref(ob, callback);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
if (callback == NULL) {
|
if (callback == NULL) {
|
||||||
insert_head(result, list);
|
insert_head(result, list);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyWeakReference *prev = (proxy == NULL) ? ref : proxy;
|
PyWeakReference *prev;
|
||||||
|
|
||||||
|
get_basic_refs(*list, &ref, &proxy);
|
||||||
|
prev = (proxy == NULL) ? ref : proxy;
|
||||||
if (prev == NULL)
|
if (prev == NULL)
|
||||||
insert_head(result, list);
|
insert_head(result, list);
|
||||||
else
|
else
|
||||||
|
@ -672,8 +679,13 @@ PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
|
||||||
/* attempt to return an existing weak reference if it exists */
|
/* attempt to return an existing weak reference if it exists */
|
||||||
result = proxy;
|
result = proxy;
|
||||||
if (result != NULL)
|
if (result != NULL)
|
||||||
Py_XINCREF(result);
|
Py_INCREF(result);
|
||||||
else {
|
else {
|
||||||
|
/* Note: new_weakref() can trigger cyclic GC, so the weakref
|
||||||
|
list on ob can be mutated. This means that the ref and
|
||||||
|
proxy pointers we got back earlier may have been collected,
|
||||||
|
so we need to compute these values again before we use
|
||||||
|
them. */
|
||||||
result = new_weakref(ob, callback);
|
result = new_weakref(ob, callback);
|
||||||
if (result != NULL) {
|
if (result != NULL) {
|
||||||
PyWeakReference *prev;
|
PyWeakReference *prev;
|
||||||
|
@ -682,6 +694,7 @@ PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
|
||||||
result->ob_type = &_PyWeakref_CallableProxyType;
|
result->ob_type = &_PyWeakref_CallableProxyType;
|
||||||
else
|
else
|
||||||
result->ob_type = &_PyWeakref_ProxyType;
|
result->ob_type = &_PyWeakref_ProxyType;
|
||||||
|
get_basic_refs(*list, &ref, &proxy);
|
||||||
if (callback == NULL)
|
if (callback == NULL)
|
||||||
prev = ref;
|
prev = ref;
|
||||||
else
|
else
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue