-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
Bug report
Bug description:
The Python C API provides the function PyGC_Disable() to temporarily disable garbage collection. Calling it causes PyGC_Collect() to become a no-op. So far so good.
Unfortunately, CPython >= 3.12 no longer respects this flag beyond direct calls to PyGC_Collect(). Let's consider, for example, the operation PyErr_CheckSignals() at line 1773. This calls _Py_RunGC, which ignores the GC enabled flag. And this indeed happens! In fact, I just spent quite a bit of time debugging an issue where the GC was supposed to be disabled for a brief moment, and yet it runs on Python 3.12. (Whether disabling the GC for a brief period of time is a good design pattern is another discussion. I would like to steer the discussion away from this and focus on documented API behavior.)
The PyErr_CheckSignals() function is called from 135 locations in the CPython codebase including very common ones like PyObject_Str(), so making any fixes in callers of this API does not look feasible.
The flag-ignoring _Py_RunGC() function is only called by two places: besides the mentioned PyErr_CheckSignals(), there is also _Py_HandlePending() in Python/ceval_gil.c.
To restore the documented behavior, I see three options:
_Py_RunGC()could be modified to exit immediately if theenabledflag is set to zero.- The implementation of
_Py_HandlePending()andPyErr_CheckSignals()could be modified to checkPyGC_IsEnabled()before calling_Py_RunGC(). - Something is setting
_PY_GC_SCHEDULED_BIT, and that causes the implementation to enter_Py_RunGC(). I'm not really sure about how that works, but perhaps this flag could be cleared inPyGC_Disable(), and Python could then avoid setting the flag.
(Tagging @pablogsal and @swtaarrs, who commited changes to the relevant code.)
CPython versions tested on:
3.12
Operating systems tested on:
Linux