From 37ae65a0301f6b3e46106b367af6c8ab48094701 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 11:35:18 +0300 Subject: [PATCH 1/2] gh-132002: Fix crash of `ContextVar` on unhashable `str` subtype --- Lib/test/test_context.py | 9 +++++++++ .../2025-04-02-11-31-15.gh-issue-132002.TMsYvE.rst | 2 ++ Python/context.c | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-04-02-11-31-15.gh-issue-132002.TMsYvE.rst diff --git a/Lib/test/test_context.py b/Lib/test/test_context.py index f9cdcc3561e9d6..73f59f2cb8af4b 100644 --- a/Lib/test/test_context.py +++ b/Lib/test/test_context.py @@ -92,6 +92,15 @@ def test_context_new_1(self): contextvars.Context(a=1) contextvars.Context(**{}) + def test_context_new_unhashable_str_subclass(self): + # gh-132002: it used to crash on unhashable str subtypes. + class weird_str(str): + def __eq__(self, other): + pass + + with self.assertRaisesRegex(TypeError, 'unhashable type'): + contextvars.ContextVar(weird_str()) + def test_context_typerrors_1(self): ctx = contextvars.Context() diff --git a/Misc/NEWS.d/next/Library/2025-04-02-11-31-15.gh-issue-132002.TMsYvE.rst b/Misc/NEWS.d/next/Library/2025-04-02-11-31-15.gh-issue-132002.TMsYvE.rst new file mode 100644 index 00000000000000..b46bc25b87f1e3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-02-11-31-15.gh-issue-132002.TMsYvE.rst @@ -0,0 +1,2 @@ +Fix crash when deallocating :class:`contextvars.ContextVar` with weird +unahashable string names. diff --git a/Python/context.c b/Python/context.c index 4110e6891a1070..4ff35877b34380 100644 --- a/Python/context.c +++ b/Python/context.c @@ -880,7 +880,7 @@ contextvar_new(PyObject *name, PyObject *def) var->var_hash = contextvar_generate_hash(var, name); if (var->var_hash == -1) { - Py_DECREF(var); + PyObject_GC_Del(var); return NULL; } From 58f539dea8fcfe8c1b19ec487e92f481a4b4f170 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 2 Apr 2025 12:36:33 +0300 Subject: [PATCH 2/2] Address review --- Python/context.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Python/context.c b/Python/context.c index 4ff35877b34380..dceaae9b42979d 100644 --- a/Python/context.c +++ b/Python/context.c @@ -878,14 +878,7 @@ contextvar_new(PyObject *name, PyObject *def) return NULL; } - var->var_hash = contextvar_generate_hash(var, name); - if (var->var_hash == -1) { - PyObject_GC_Del(var); - return NULL; - } - var->var_name = Py_NewRef(name); - var->var_default = Py_XNewRef(def); #ifndef Py_GIL_DISABLED @@ -894,6 +887,12 @@ contextvar_new(PyObject *name, PyObject *def) var->var_cached_tsver = 0; #endif + var->var_hash = contextvar_generate_hash(var, name); + if (var->var_hash == -1) { + Py_DECREF(var); + return NULL; + } + if (_PyObject_GC_MAY_BE_TRACKED(name) || (def != NULL && _PyObject_GC_MAY_BE_TRACKED(def))) {