]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-123657: Fix crash and refleak in `decimal.getcontext()` (GH-123703) (GH...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 6 Sep 2024 13:18:01 +0000 (15:18 +0200)
committerGitHub <noreply@github.com>
Fri, 6 Sep 2024 13:18:01 +0000 (15:18 +0200)
(cherry picked from commit 853588e24c907be158b3a08601797ea5b47a0eba)

Co-authored-by: neonene <53406459+neonene@users.noreply.github.com>
Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst [new file with mode: 0644]
Modules/_decimal/_decimal.c

diff --git a/Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst b/Misc/NEWS.d/next/Library/2024-09-04-18-23-43.gh-issue-123657.Oks4So.rst
new file mode 100644 (file)
index 0000000..efebd21
--- /dev/null
@@ -0,0 +1,2 @@
+Fix crash and memory leak in :func:`decimal.getcontext`. It crashed when using
+a thread-local context by ``--with-decimal-contextvar=no``.
index 05664bf9ed38aed4669340ad40da8365213c0110..29ae5f402a06f9b8540caf5b8571edfa8f71367c 100644 (file)
@@ -76,8 +76,9 @@ typedef struct {
 #ifndef WITH_DECIMAL_CONTEXTVAR
     /* Key for thread state dictionary */
     PyObject *tls_context_key;
-    /* Invariant: NULL or the most recently accessed thread local context */
-    struct PyDecContextObject *cached_context;
+    /* Invariant: NULL or a strong reference to the most recently accessed
+       thread local context. */
+    struct PyDecContextObject *cached_context;  /* Not borrowed */
 #else
     PyObject *current_context_var;
 #endif
@@ -1419,12 +1420,6 @@ context_dealloc(PyDecContextObject *self)
 {
     PyTypeObject *tp = Py_TYPE(self);
     PyObject_GC_UnTrack(self);
-#ifndef WITH_DECIMAL_CONTEXTVAR
-    decimal_state *state = get_module_state_by_def(Py_TYPE(self));
-    if (self == state->cached_context) {
-        state->cached_context = NULL;
-    }
-#endif
     (void)context_clear(self);
     tp->tp_free(self);
     Py_DECREF(tp);
@@ -1701,7 +1696,8 @@ current_context_from_dict(decimal_state *modstate)
 
     /* Cache the context of the current thread, assuming that it
      * will be accessed several times before a thread switch. */
-    modstate->cached_context = (PyDecContextObject *)tl_context;
+    Py_XSETREF(modstate->cached_context,
+               (PyDecContextObject *)Py_NewRef(tl_context));
     modstate->cached_context->tstate = tstate;
 
     /* Borrowed reference with refcount==1 */
@@ -1769,7 +1765,7 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v)
         Py_INCREF(v);
     }
 
-    state->cached_context = NULL;
+    Py_CLEAR(state->cached_context);
     if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) {
         Py_DECREF(v);
         return NULL;
@@ -6122,6 +6118,16 @@ decimal_traverse(PyObject *module, visitproc visit, void *arg)
     Py_VISIT(state->Rational);
     Py_VISIT(state->SignalTuple);
 
+    if (state->signal_map != NULL) {
+        for (DecCondMap *cm = state->signal_map; cm->name != NULL; cm++) {
+            Py_VISIT(cm->ex);
+        }
+    }
+    if (state->cond_map != NULL) {
+        for (DecCondMap *cm = state->cond_map + 1; cm->name != NULL; cm++) {
+            Py_VISIT(cm->ex);
+        }
+    }
     return 0;
 }