Skip to content

Commit d9411ae

Browse files
authored
gh-130312: SET_ADD should not lock (#130136)
SET_ADD should not lock
1 parent 7101cba commit d9411ae

File tree

5 files changed

+76
-59
lines changed

5 files changed

+76
-59
lines changed

Include/internal/pycore_setobject.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ PyAPI_FUNC(int) _PySet_Contains(PySetObject *so, PyObject *key);
3333
// Clears the set without acquiring locks. Used by _PyCode_Fini.
3434
extern void _PySet_ClearInternal(PySetObject *so);
3535

36+
PyAPI_FUNC(int) _PySet_AddTakeRef(PySetObject *so, PyObject *key);
37+
3638
#ifdef __cplusplus
3739
}
3840
#endif

Objects/setobject.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
122122
static int set_table_resize(PySetObject *, Py_ssize_t);
123123

124124
static int
125-
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
125+
set_add_entry_takeref(PySetObject *so, PyObject *key, Py_hash_t hash)
126126
{
127127
setentry *table;
128128
setentry *freeslot;
@@ -133,12 +133,6 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
133133
int probes;
134134
int cmp;
135135

136-
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
137-
138-
/* Pre-increment is necessary to prevent arbitrary code in the rich
139-
comparison from deallocating the key just before the insertion. */
140-
Py_INCREF(key);
141-
142136
restart:
143137

144138
mask = so->mask;
@@ -209,6 +203,27 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
209203
return -1;
210204
}
211205

206+
static int
207+
set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
208+
{
209+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
210+
211+
return set_add_entry_takeref(so, Py_NewRef(key), hash);
212+
}
213+
214+
int
215+
_PySet_AddTakeRef(PySetObject *so, PyObject *key)
216+
{
217+
Py_hash_t hash = _PyObject_HashFast(key);
218+
if (hash == -1) {
219+
Py_DECREF(key);
220+
return -1;
221+
}
222+
// We don't pre-increment here, the caller holds a strong
223+
// reference to the object which we are stealing.
224+
return set_add_entry_takeref(so, key, hash);
225+
}
226+
212227
/*
213228
Internal routine used by set_table_resize() to insert an item which is
214229
known to be absent from the set. Besides the performance benefit,

Python/bytecodes.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -975,9 +975,8 @@ dummy_func(
975975
}
976976

977977
inst(SET_ADD, (set, unused[oparg-1], v -- set, unused[oparg-1])) {
978-
int err = PySet_Add(PyStackRef_AsPyObjectBorrow(set),
979-
PyStackRef_AsPyObjectBorrow(v));
980-
PyStackRef_CLOSE(v);
978+
int err = _PySet_AddTakeRef((PySetObject *)PyStackRef_AsPyObjectBorrow(set),
979+
PyStackRef_AsPyObjectSteal(v));
981980
ERROR_IF(err, error);
982981
}
983982

@@ -1916,17 +1915,24 @@ dummy_func(
19161915
DECREF_INPUTS();
19171916
ERROR_IF(true, error);
19181917
}
1918+
19191919
int err = 0;
1920-
for (int i = 0; i < oparg; i++) {
1920+
for (Py_ssize_t i = 0; i < oparg; i++) {
1921+
_PyStackRef value = values[i];
1922+
values[i] = PyStackRef_NULL;
19211923
if (err == 0) {
1922-
err = PySet_Add(set_o, PyStackRef_AsPyObjectBorrow(values[i]));
1924+
err = _PySet_AddTakeRef((PySetObject *)set_o, PyStackRef_AsPyObjectSteal(value));
1925+
}
1926+
else {
1927+
PyStackRef_CLOSE(value);
19231928
}
19241929
}
1925-
DECREF_INPUTS();
1926-
if (err != 0) {
1930+
if (err) {
19271931
Py_DECREF(set_o);
19281932
ERROR_IF(true, error);
19291933
}
1934+
1935+
INPUTS_DEAD();
19301936
set = PyStackRef_FromPyObjectStealMortal(set_o);
19311937
}
19321938

Python/executor_cases.c.h

Lines changed: 20 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 19 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)