Skip to content

Commit 3d713c1

Browse files
committed
gh-158490: Don't freeze a shared set in the frozenset() fast path
make_frozenset() assumed that the set built for frozenset() of a set display or comprehension is uniquely referenced and froze it in place. A trace function or pdb can still hold the set returned by a comprehension that is not inlined, such as one in a class annotation. Copy the set in that case.
1 parent 77c0675 commit 3d713c1

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎Lib/test/test_builtin.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,29 @@ async def f_set():
329329
with self.assertRaises(TypeError):
330330
run_yielding_async_fn(f)
331331

332+
def test_frozenset_optimization_shared_set(self):
333+
# gh-158490: frozenset({... for ...}) must not freeze a set that
334+
# something else still references, here a trace function
335+
kept = []
336+
def tracer(frame, event, arg):
337+
if event == 'return' and type(arg) is set:
338+
kept.append(arg)
339+
return tracer
340+
341+
class C:
342+
x: frozenset({i for i in range(3)})
343+
344+
old_trace = sys.gettrace()
345+
sys.settrace(tracer)
346+
try:
347+
fs = C.__annotations__['x']
348+
finally:
349+
sys.settrace(old_trace)
350+
self.assertEqual(fs, frozenset({0, 1, 2}))
351+
self.assertEqual(len(kept), 1)
352+
self.assertIs(type(kept[0]), set)
353+
self.assertIsNot(kept[0], fs)
354+
332355
def test_ascii(self):
333356
self.assertEqual(ascii(''), '\'\'')
334357
self.assertEqual(ascii(0), '0')

‎Python/intrinsics.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ static PyObject *
212212
make_frozenset(PyThreadState* Py_UNUSED(ignored), PyObject *set)
213213
{
214214
assert(PySet_CheckExact(set));
215-
assert(_PyObject_IsUniquelyReferenced(set));
215+
if (!_PyObject_IsUniquelyReferenced(set)) {
216+
return PyFrozenSet_New(set);
217+
}
216218
return _PySet_Freeze(set);
217219
}
218220

0 commit comments

Comments
 (0)