@@ -47,7 +47,7 @@ using greenlet::MainGreenlet;
4747using greenlet::BrokenGreenlet;
4848using greenlet::ThreadState;
4949using greenlet::PythonState;
50-
50+ using greenlet::refs::PyCriticalObjectSection;
5151
5252
5353static PyGreenlet*
@@ -372,6 +372,29 @@ PyDoc_STRVAR(
372372static PyObject*
373373green_switch (PyGreenlet* self, PyObject* args, PyObject* kwargs)
374374{
375+ // Our use of Greenlet::args() makes this method non-reentrant.
376+ // Therefore, check to be sure the switch will be allowed ---
377+ // we're calling from the same thread that ``self`` belongs to ---
378+ // BEFORE doing anything with args(). If we don't do this, we can
379+ // find args() getting clobbered by switches that will never
380+ // succeed.
381+ //
382+ // TODO: We're only doing this for free-threaded builds because
383+ // those are the only ones that have demonstrated an issue,
384+ // trusting our later checks in g_switch to perform the same
385+ // function and the GIL to keep us from being reentered in regular
386+ // builds. BUT should we always do this as an extra measure of
387+ // safety in case we run code at unexpected times (e.g., a GC?)
388+ #ifdef Py_GIL_DISABLED
389+ try {
390+ self->pimpl ->check_switch_allowed ();
391+ }
392+ catch (const PyErrOccurred&) {
393+ return nullptr ;
394+ }
395+ #endif
396+
397+
375398 using greenlet::SwitchingArgs;
376399 SwitchingArgs switch_args (OwnedObject::owning (args), OwnedObject::owning (kwargs));
377400 self->pimpl ->may_switch_away ();
@@ -454,6 +477,16 @@ PyDoc_STRVAR(
454477static PyObject*
455478green_throw (PyGreenlet* self, PyObject* args)
456479{
480+ // See green_switch for why we call this early.
481+ #ifdef Py_GIL_DISABLED
482+ try {
483+ self->pimpl ->check_switch_allowed ();
484+ }
485+ catch (const PyErrOccurred&) {
486+ return nullptr ;
487+ }
488+ #endif
489+
457490 PyArgParseParam typ (mod_globs->PyExc_GreenletExit );
458491 PyArgParseParam val;
459492 PyArgParseParam tb;
@@ -489,6 +522,7 @@ green_bool(PyGreenlet* self)
489522static PyObject*
490523green_getdict (PyGreenlet* self, void * UNUSED (context))
491524{
525+ PyCriticalObjectSection cs (self);
492526 if (self->dict == NULL ) {
493527 self->dict = PyDict_New ();
494528 if (self->dict == NULL ) {
@@ -502,8 +536,6 @@ green_getdict(PyGreenlet* self, void* UNUSED(context))
502536static int
503537green_setdict (PyGreenlet* self, PyObject* val, void * UNUSED (context))
504538{
505- PyObject* tmp;
506-
507539 if (val == NULL ) {
508540 PyErr_SetString (PyExc_TypeError, " __dict__ may not be deleted" );
509541 return -1 ;
@@ -512,7 +544,8 @@ green_setdict(PyGreenlet* self, PyObject* val, void* UNUSED(context))
512544 PyErr_SetString (PyExc_TypeError, " __dict__ must be a dictionary" );
513545 return -1 ;
514546 }
515- tmp = self->dict ;
547+ PyCriticalObjectSection cs (self);
548+ PyObject* tmp = self->dict ;
516549 Py_INCREF (val);
517550 self->dict = val;
518551 Py_XDECREF (tmp);
@@ -535,6 +568,7 @@ _green_not_dead(BorrowedGreenlet self)
535568static PyObject*
536569green_getdead (PyGreenlet* self, void * UNUSED (context))
537570{
571+ PyCriticalObjectSection cs (self);
538572 if (_green_not_dead (self)) {
539573 Py_RETURN_FALSE;
540574 }
@@ -553,6 +587,7 @@ green_get_stack_saved(PyGreenlet* self, void* UNUSED(context))
553587static PyObject*
554588green_getrun (PyGreenlet* self, void * UNUSED (context))
555589{
590+ PyCriticalObjectSection cs (self);
556591 try {
557592 OwnedObject result (BorrowedGreenlet (self)->run ());
558593 return result.relinquish_ownership ();
@@ -566,6 +601,7 @@ green_getrun(PyGreenlet* self, void* UNUSED(context))
566601static int
567602green_setrun (PyGreenlet* self, PyObject* nrun, void * UNUSED (context))
568603{
604+ PyCriticalObjectSection cs (self);
569605 try {
570606 BorrowedGreenlet (self)->run (nrun);
571607 return 0 ;
@@ -578,13 +614,15 @@ green_setrun(PyGreenlet* self, PyObject* nrun, void* UNUSED(context))
578614static PyObject*
579615green_getparent (PyGreenlet* self, void * UNUSED (context))
580616{
617+ PyCriticalObjectSection cs (self);
581618 return BorrowedGreenlet (self)->parent ().acquire_or_None ();
582619}
583620
584621
585622static int
586623green_setparent (PyGreenlet* self, PyObject* nparent, void * UNUSED (context))
587624{
625+ PyCriticalObjectSection cs (self);
588626 try {
589627 BorrowedGreenlet (self)->parent (nparent);
590628 }
@@ -598,6 +636,7 @@ green_setparent(PyGreenlet* self, PyObject* nparent, void* UNUSED(context))
598636static PyObject*
599637green_getcontext (const PyGreenlet* self, void * UNUSED (context))
600638{
639+ PyCriticalObjectSection cs (self);
601640 const Greenlet *const g = self->pimpl ;
602641 try {
603642 OwnedObject result (g->context ());
@@ -611,6 +650,7 @@ green_getcontext(const PyGreenlet* self, void* UNUSED(context))
611650static int
612651green_setcontext (PyGreenlet* self, PyObject* nctx, void * UNUSED (context))
613652{
653+ PyCriticalObjectSection cs (self);
614654 try {
615655 BorrowedGreenlet (self)->context (nctx);
616656 return 0 ;
@@ -624,6 +664,7 @@ green_setcontext(PyGreenlet* self, PyObject* nctx, void* UNUSED(context))
624664static PyObject*
625665green_getframe (PyGreenlet* self, void * UNUSED (context))
626666{
667+ PyCriticalObjectSection cs (self);
627668 const PythonState::OwnedFrame& top_frame = BorrowedGreenlet (self)->top_frame ();
628669 return top_frame.acquire_or_None ();
629670}
0 commit comments