Skip to content

Commit 853588e

Browse files
authored
gh-123657: Fix crash and refleak in decimal.getcontext() (GH-123703)
1 parent 8311b11 commit 853588e

File tree

2 files changed

+18
-10
lines changed

2 files changed

+18
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash and memory leak in :func:`decimal.getcontext`. It crashed when using
2+
a thread-local context by ``--with-decimal-contextvar=no``.

Modules/_decimal/_decimal.c

+16-10
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ typedef struct {
7676
#ifndef WITH_DECIMAL_CONTEXTVAR
7777
/* Key for thread state dictionary */
7878
PyObject *tls_context_key;
79-
/* Invariant: NULL or the most recently accessed thread local context */
80-
struct PyDecContextObject *cached_context;
79+
/* Invariant: NULL or a strong reference to the most recently accessed
80+
thread local context. */
81+
struct PyDecContextObject *cached_context; /* Not borrowed */
8182
#else
8283
PyObject *current_context_var;
8384
#endif
@@ -1419,12 +1420,6 @@ context_dealloc(PyDecContextObject *self)
14191420
{
14201421
PyTypeObject *tp = Py_TYPE(self);
14211422
PyObject_GC_UnTrack(self);
1422-
#ifndef WITH_DECIMAL_CONTEXTVAR
1423-
decimal_state *state = get_module_state_by_def(Py_TYPE(self));
1424-
if (self == state->cached_context) {
1425-
state->cached_context = NULL;
1426-
}
1427-
#endif
14281423
(void)context_clear(self);
14291424
tp->tp_free(self);
14301425
Py_DECREF(tp);
@@ -1701,7 +1696,8 @@ current_context_from_dict(decimal_state *modstate)
17011696

17021697
/* Cache the context of the current thread, assuming that it
17031698
* will be accessed several times before a thread switch. */
1704-
modstate->cached_context = (PyDecContextObject *)tl_context;
1699+
Py_XSETREF(modstate->cached_context,
1700+
(PyDecContextObject *)Py_NewRef(tl_context));
17051701
modstate->cached_context->tstate = tstate;
17061702

17071703
/* Borrowed reference with refcount==1 */
@@ -1769,7 +1765,7 @@ PyDec_SetCurrentContext(PyObject *self, PyObject *v)
17691765
Py_INCREF(v);
17701766
}
17711767

1772-
state->cached_context = NULL;
1768+
Py_CLEAR(state->cached_context);
17731769
if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) {
17741770
Py_DECREF(v);
17751771
return NULL;
@@ -6122,6 +6118,16 @@ decimal_traverse(PyObject *module, visitproc visit, void *arg)
61226118
Py_VISIT(state->Rational);
61236119
Py_VISIT(state->SignalTuple);
61246120

6121+
if (state->signal_map != NULL) {
6122+
for (DecCondMap *cm = state->signal_map; cm->name != NULL; cm++) {
6123+
Py_VISIT(cm->ex);
6124+
}
6125+
}
6126+
if (state->cond_map != NULL) {
6127+
for (DecCondMap *cm = state->cond_map + 1; cm->name != NULL; cm++) {
6128+
Py_VISIT(cm->ex);
6129+
}
6130+
}
61256131
return 0;
61266132
}
61276133

0 commit comments

Comments
 (0)