mirror of
https://github.com/python/cpython.git
synced 2026-01-26 04:48:57 +00:00
gh-142829: Fix use-after-free in Context.__eq__ via re-entrant ContextVar.set (#142905)
This commit is contained in:
parent
a9ca49d9c6
commit
a4086d7f89
@ -556,6 +556,36 @@ class ContextTest(unittest.TestCase):
|
||||
|
||||
ctx.run(fun)
|
||||
|
||||
def test_context_eq_reentrant_contextvar_set(self):
|
||||
var = contextvars.ContextVar("v")
|
||||
ctx1 = contextvars.Context()
|
||||
ctx2 = contextvars.Context()
|
||||
|
||||
class ReentrantEq:
|
||||
def __eq__(self, other):
|
||||
ctx1.run(lambda: var.set(object()))
|
||||
return True
|
||||
|
||||
ctx1.run(var.set, ReentrantEq())
|
||||
ctx2.run(var.set, object())
|
||||
ctx1 == ctx2
|
||||
|
||||
def test_context_eq_reentrant_contextvar_set_in_hash(self):
|
||||
var = contextvars.ContextVar("v")
|
||||
ctx1 = contextvars.Context()
|
||||
ctx2 = contextvars.Context()
|
||||
|
||||
class ReentrantHash:
|
||||
def __hash__(self):
|
||||
ctx1.run(lambda: var.set(object()))
|
||||
return 0
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, ReentrantHash)
|
||||
|
||||
ctx1.run(var.set, ReentrantHash())
|
||||
ctx2.run(var.set, ReentrantHash())
|
||||
ctx1 == ctx2
|
||||
|
||||
|
||||
# HAMT Tests
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
Fix a use-after-free crash in :class:`contextvars.Context` comparison when a
|
||||
custom ``__eq__`` method modifies the context via
|
||||
:meth:`~contextvars.ContextVar.set`.
|
||||
@ -2328,6 +2328,10 @@ _PyHamt_Eq(PyHamtObject *v, PyHamtObject *w)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py_INCREF(v);
|
||||
Py_INCREF(w);
|
||||
|
||||
int res = 1;
|
||||
PyHamtIteratorState iter;
|
||||
hamt_iter_t iter_res;
|
||||
hamt_find_t find_res;
|
||||
@ -2343,25 +2347,38 @@ _PyHamt_Eq(PyHamtObject *v, PyHamtObject *w)
|
||||
find_res = hamt_find(w, v_key, &w_val);
|
||||
switch (find_res) {
|
||||
case F_ERROR:
|
||||
return -1;
|
||||
res = -1;
|
||||
goto done;
|
||||
|
||||
case F_NOT_FOUND:
|
||||
return 0;
|
||||
res = 0;
|
||||
goto done;
|
||||
|
||||
case F_FOUND: {
|
||||
Py_INCREF(v_key);
|
||||
Py_INCREF(v_val);
|
||||
Py_INCREF(w_val);
|
||||
int cmp = PyObject_RichCompareBool(v_val, w_val, Py_EQ);
|
||||
Py_DECREF(v_key);
|
||||
Py_DECREF(v_val);
|
||||
Py_DECREF(w_val);
|
||||
if (cmp < 0) {
|
||||
return -1;
|
||||
res = -1;
|
||||
goto done;
|
||||
}
|
||||
if (cmp == 0) {
|
||||
return 0;
|
||||
res = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (iter_res != I_END);
|
||||
|
||||
return 1;
|
||||
done:
|
||||
Py_DECREF(v);
|
||||
Py_DECREF(w);
|
||||
return res;
|
||||
}
|
||||
|
||||
Py_ssize_t
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user