Skip to content

Commit 3d0d584

Browse files
committed
Add tests
1 parent c8ccd02 commit 3d0d584

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

Lib/test/test_free_threading/test_races.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,25 @@ def mutate():
270270

271271
do_race(set_value, mutate)
272272

273+
def test_generic_getattr(self):
274+
"""Test generic attribute load"""
275+
import concurrent.futures
276+
277+
num_threads = 100
278+
279+
280+
def closure(b, o):
281+
b.wait()
282+
getattr(o, "foo", None)
283+
o.foo = 42
284+
285+
with concurrent.futures.ThreadPoolExecutor(max_workers=num_threads) as executor:
286+
for _ in range(100):
287+
b = threading.Barrier(num_threads)
288+
o = functools.partial(lambda x: x, 42)
289+
for _ in range(num_threads):
290+
executor.submit(functools.partial(closure, b, o))
291+
273292

274293
if __name__ == "__main__":
275294
unittest.main()

Objects/object.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,13 +1716,13 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
17161716
}
17171717
else {
17181718
Py_BEGIN_CRITICAL_SECTION(obj);
1719-
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
1720-
if (dictptr) {
17211719
#ifdef DISABLE_GIL
1722-
dict = (PyObject *)_Py_atomic_load_ptr(dictptr);
1720+
PyObject **dictptr = _Py_atomic_load_ptr(_PyObject_ComputedDictPointer(obj));
17231721
#else
1724-
dict = *dictptr;
1722+
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
17251723
#endif
1724+
if (dictptr) {
1725+
dict = *dictptr;
17261726
}
17271727
Py_END_CRITICAL_SECTION();
17281728
}

0 commit comments

Comments
 (0)