Skip to content

Commit 8b0ab08

Browse files
[3.14] gh-158929: Fix subinterpreter thread safety issues in syslog (GH-159000) (GH-159126)
(cherry picked from commit 224b4b0) Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
1 parent 6b96dc3 commit 8b0ab08

3 files changed

Lines changed: 31 additions & 10 deletions

File tree

‎Lib/test/test_syslog.py‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,29 @@ def test_subinterpreter_closelog(self):
142142
finally:
143143
syslog.closelog()
144144

145+
@threading_helper.requires_working_threading()
146+
def test_subinterpreter_concurrent_syslog(self):
147+
# gh-158929: This used to crash.
148+
from concurrent import interpreters
149+
150+
interp = interpreters.create()
151+
try:
152+
def in_interpreter():
153+
import syslog
154+
155+
for _ in range(40000):
156+
try:
157+
syslog.syslog('my hovercraft is full of eels')
158+
except RuntimeError:
159+
pass
160+
thread = interp.call_in_thread(in_interpreter)
161+
for i in range(40000):
162+
syslog.openlog(f"python{i}")
163+
syslog.closelog()
164+
thread.join()
165+
finally:
166+
interp.close()
167+
145168

146169
if __name__ == "__main__":
147170
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash when calling :func:`syslog.syslog` while a subinterpreter in
2+
another thread calls :func:`syslog.openlog` or :func:`syslog.closelog`.

‎Modules/syslogmodule.c‎

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ module syslog
7070
/* only one instance, only one syslog, so globals should be ok,
7171
* these fields are writable from the main interpreter only. */
7272
static PyObject *S_ident_o = NULL; // identifier, held by openlog()
73-
static char S_log_open = 0;
73+
static int S_log_open = 0;
7474

7575
static inline int
7676
is_main_interpreter(void)
@@ -190,7 +190,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt,
190190
}
191191

192192
openlog(ident_str, logopt, facility);
193-
S_log_open = 1;
193+
_Py_atomic_store_int(&S_log_open, 1);
194194
Py_XSETREF(S_ident_o, ident);
195195

196196
Py_RETURN_NONE;
@@ -223,7 +223,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
223223
}
224224

225225
/* if log is not opened, open it now */
226-
if (!S_log_open) {
226+
if (!_Py_atomic_load_int(&S_log_open)) {
227227
if (!is_main_interpreter()) {
228228
PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() "
229229
"until the syslog is opened by the main interpreter");
@@ -236,10 +236,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
236236
Py_DECREF(openlog_ret);
237237
}
238238

239-
/* Incref ident, because it can be decrefed if syslog.openlog() is
240-
* called when the GIL is released.
241-
*/
242-
PyObject *ident = Py_XNewRef(S_ident_o);
243239
#ifdef __APPLE__
244240
// gh-98178: On macOS, libc syslog() is not thread-safe
245241
syslog(priority, "%s", message);
@@ -248,7 +244,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority,
248244
syslog(priority, "%s", message);
249245
Py_END_ALLOW_THREADS;
250246
#endif
251-
Py_XDECREF(ident);
252247
Py_RETURN_NONE;
253248
}
254249

@@ -274,10 +269,11 @@ syslog_closelog_impl(PyObject *module)
274269
if (PySys_Audit("syslog.closelog", NULL) < 0) {
275270
return NULL;
276271
}
277-
if (S_log_open) {
272+
273+
int was_open = _Py_atomic_exchange_int(&S_log_open, 0);
274+
if (was_open) {
278275
closelog();
279276
Py_CLEAR(S_ident_o);
280-
S_log_open = 0;
281277
}
282278
Py_RETURN_NONE;
283279
}

0 commit comments

Comments
 (0)