Skip to content

Commit

Permalink
Save and restore the tstate->cframe as part of the greenlet structure…
Browse files Browse the repository at this point in the history
… on 3.10.

This fixes the crashes that the python.org interpreter was having in the test suite.

This does not require a major version bump, even though the structure changed, because there hasn't been a 3.10 compatible release of greenlet yet.
  • Loading branch information
jamadden committed May 5, 2021
1 parent 6c5f096 commit 352b974
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
20 changes: 18 additions & 2 deletions src/greenlet/greenlet.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,13 @@ extern PyTypeObject PyGreenlet_Type;
/*
Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member.
See https://github.com/python/cpython/pull/25276
We have to save and restore this as well.
*/
#define TSTATE_USE_TRACING(tstate) (tstate->cframe->use_tracing)
#define GREENLET_USE_CFRAME 1
#else
#define TSTATE_USE_TRACING(tstate) (tstate->use_tracing)
#define GREENLET_USE_CFRAME 0
#endif

#ifndef Py_SET_REFCNT
Expand Down Expand Up @@ -514,6 +517,9 @@ g_switchstack(void)
current->exc_type = tstate->exc_type;
current->exc_value = tstate->exc_value;
current->exc_traceback = tstate->exc_traceback;
#endif
#if GREENLET_USE_CFRAME
current->cframe = tstate->cframe;
#endif
}
err = slp_switch();
Expand Down Expand Up @@ -558,6 +564,10 @@ g_switchstack(void)
#endif
green_clear_exc(target);

#if GREENLET_USE_CFRAME
tstate->cframe = target->cframe;
#endif

assert(ts_origin == NULL);
Py_INCREF(target);
ts_current = target;
Expand Down Expand Up @@ -907,6 +917,9 @@ green_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
}
Py_INCREF(ts_current);
((PyGreenlet*)o)->parent = ts_current;
#if GREENLET_USE_CFRAME
((PyGreenlet*)o)->cframe = &PyThreadState_GET()->root_cframe;
#endif
}
return o;
}
Expand Down Expand Up @@ -1611,8 +1624,9 @@ PyGreenlet_SetParent(PyGreenlet* g, PyGreenlet* nparent)
static PyGreenlet*
PyGreenlet_New(PyObject* run, PyGreenlet* parent)
{
/* XXX: Why doesn't this call green_new()? There's some duplicate
code. */
PyGreenlet* g = NULL;

g = (PyGreenlet*)PyType_GenericAlloc(&PyGreenlet_Type, 0);
if (g == NULL) {
return NULL;
Expand All @@ -1635,7 +1649,9 @@ PyGreenlet_New(PyObject* run, PyGreenlet* parent)
return NULL;
}
}

#if GREENLET_USE_CFRAME
g->cframe = &PyThreadState_GET()->root_cframe;
#endif
return g;
}

Expand Down
3 changes: 3 additions & 0 deletions src/greenlet/greenlet.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ typedef struct _greenlet {
#if PY_VERSION_HEX >= 0x030700A3
PyObject* context;
#endif
#if PY_VERSION_HEX >= 0x30A00B1
CFrame* cframe;
#endif
} PyGreenlet;

#define PyGreenlet_Check(op) PyObject_TypeCheck(op, &PyGreenlet_Type)
Expand Down
3 changes: 3 additions & 0 deletions src/greenlet/tests/test_extension_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ def foo():
str(seen[0]),
'take that sucka!',
"message doesn't match")

if __name__ == '__main__':
unittest.main()

0 comments on commit 352b974

Please sign in to comment.