https://github.com/python/cpython/commit/224b4b0ab1640db514da8639924265bac9d83134
commit: 224b4b0ab1640db514da8639924265bac9d83134
branch: main
author: Peter Bierma <[email protected]>
committer: ZeroIntensity <[email protected]>
date: 2026-10-10T11:41:34-04:00
summary:

gh-158929: Fix subinterpreter thread safety issues in `syslog` (GH-159000)

files:
A Misc/NEWS.d/next/Library/2026-10-07-20-32-20.gh-issue-158929.6dwqfQ.rst
M Lib/test/test_syslog.py
M Modules/syslogmodule.c

diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py
index 54db80fa9df1afa..e6e3ccab35fa9f8 100644
--- a/Lib/test/test_syslog.py
+++ b/Lib/test/test_syslog.py
@@ -142,6 +142,29 @@ def test_subinterpreter_closelog(self):
         finally:
             syslog.closelog()
 
+    @threading_helper.requires_working_threading()
+    def test_subinterpreter_concurrent_syslog(self):
+        # gh-158929: This used to crash.
+        from concurrent import interpreters
+
+        interp = interpreters.create()
+        try:
+            def in_interpreter():
+                import syslog
+
+                for _ in range(40000):
+                    try:
+                        syslog.syslog('my hovercraft is full of eels')
+                    except RuntimeError:
+                        pass
+            thread = interp.call_in_thread(in_interpreter)
+            for i in range(40000):
+                syslog.openlog(f"python{i}")
+                syslog.closelog()
+            thread.join()
+        finally:
+            interp.close()
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-07-20-32-20.gh-issue-158929.6dwqfQ.rst 
b/Misc/NEWS.d/next/Library/2026-10-07-20-32-20.gh-issue-158929.6dwqfQ.rst
new file mode 100644
index 000000000000000..538db4e4c39dea3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-07-20-32-20.gh-issue-158929.6dwqfQ.rst
@@ -0,0 +1,2 @@
+Fix crash when calling :func:`syslog.syslog` while a subinterpreter in
+another thread calls :func:`syslog.openlog` or :func:`syslog.closelog`.
diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c
index 2d13f9eda758ddc..cdf76cf2d1acc8b 100644
--- a/Modules/syslogmodule.c
+++ b/Modules/syslogmodule.c
@@ -69,7 +69,7 @@ module syslog
 /*  only one instance, only one syslog, so globals should be ok,
  *  these fields are writable from the main interpreter only. */
 static PyObject *S_ident_o = NULL;  // identifier, held by openlog()
-static char S_log_open = 0;
+static int S_log_open = 0;
 
 static inline int
 is_main_interpreter(void)
@@ -189,7 +189,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long 
logopt,
     }
 
     openlog(ident_str, logopt, facility);
-    S_log_open = 1;
+    _Py_atomic_store_int(&S_log_open, 1);
     Py_XSETREF(S_ident_o, ident);
 
     Py_RETURN_NONE;
@@ -222,7 +222,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int 
priority,
     }
 
     /*  if log is not opened, open it now  */
-    if (!S_log_open) {
+    if (!_Py_atomic_load_int(&S_log_open)) {
         if (!is_main_interpreter()) {
             PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use 
syslog.syslog() "
                                                 "until the syslog is opened by 
the main interpreter");
@@ -235,10 +235,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int 
priority,
         Py_DECREF(openlog_ret);
     }
 
-    /* Incref ident, because it can be decrefed if syslog.openlog() is
-     * called when the GIL is released.
-     */
-    PyObject *ident = Py_XNewRef(S_ident_o);
 #ifdef __APPLE__
     // gh-98178: On macOS, libc syslog() is not thread-safe
     syslog(priority, "%s", message);
@@ -247,7 +243,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int 
priority,
     syslog(priority, "%s", message);
     Py_END_ALLOW_THREADS;
 #endif
-    Py_XDECREF(ident);
     Py_RETURN_NONE;
 }
 
@@ -273,10 +268,11 @@ syslog_closelog_impl(PyObject *module)
     if (PySys_Audit("syslog.closelog", NULL) < 0) {
         return NULL;
     }
-    if (S_log_open) {
+
+    int was_open = _Py_atomic_exchange_int(&S_log_open, 0);
+    if (was_open) {
         closelog();
         Py_CLEAR(S_ident_o);
-        S_log_open = 0;
     }
     Py_RETURN_NONE;
 }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to