From ced41bc32973a58e920d53aebc7f4ca054f8b04d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 22:26:38 +0900 Subject: [PATCH 01/23] gh-99127: Port syslog module to use module state. --- ...2-11-05-22-26-35.gh-issue-99127.Btk7ih.rst | 1 + Modules/syslogmodule.c | 65 +++++++++++++++---- 2 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst new file mode 100644 index 00000000000000..0eab0cac402fd0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst @@ -0,0 +1 @@ +Port :mod:`syslog` to use module state. Patch by Dong-hee Na. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 5137d01c6887c6..a2a216e784d5c5 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -61,10 +61,18 @@ module syslog #include "clinic/syslogmodule.c.h" -/* only one instance, only one syslog, so globals should be ok */ -static PyObject *S_ident_o = NULL; /* identifier, held by openlog() */ -static char S_log_open = 0; +typedef struct { + PyObject *S_ident_o; /* identifier, held by openlog() */ + char S_log_open; +} _syslog_state; +static inline _syslog_state* +get_syslog_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_syslog_state *)state; +} static PyObject * syslog_get_argv(void) @@ -162,8 +170,9 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, } openlog(ident_str, logopt, facility); - S_log_open = 1; - Py_XSETREF(S_ident_o, ident); + _syslog_state *state = get_syslog_state(module); + state->S_log_open = 1; + Py_XSETREF(state->S_ident_o, ident); Py_RETURN_NONE; } @@ -193,8 +202,9 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } + _syslog_state *state = get_syslog_state(module); /* if log is not opened, open it now */ - if (!S_log_open) { + if (!state->S_log_open) { PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); if (openlog_ret == NULL) { return NULL; @@ -205,7 +215,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, /* Incref ident, because it can be decrefed if syslog.openlog() is * called when the GIL is released. */ - PyObject *ident = S_ident_o; + PyObject *ident = state->S_ident_o; Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe @@ -233,10 +243,12 @@ syslog_closelog_impl(PyObject *module) if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } - if (S_log_open) { + + _syslog_state *state = get_syslog_state(module); + if (state->S_log_open) { closelog(); - Py_CLEAR(S_ident_o); - S_log_open = 0; + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; } Py_RETURN_NONE; } @@ -315,6 +327,11 @@ syslog_exec(PyObject *module) return -1; \ } \ } while (0) + + _syslog_state *state = get_syslog_state(module); + state->S_ident_o = NULL; + state->S_log_open = 0; + /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); @@ -380,6 +397,29 @@ syslog_exec(PyObject *module) return 0; } +static int +_syslog_traverse(PyObject *module, visitproc visit, void *arg) +{ + _syslog_state *state = get_syslog_state(module); + Py_VISIT(state->S_ident_o); + return 0; +} + +static int +_syslog_clear(PyObject *module) +{ + _syslog_state *state = get_syslog_state(module); + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; + return 0; +} + +static void +_syslog_free(void *module) +{ + _syslog_clear((PyObject *)module); +} + static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, {0, NULL} @@ -390,9 +430,12 @@ static PyModuleDef_Slot syslog_slots[] = { static struct PyModuleDef syslogmodule = { PyModuleDef_HEAD_INIT, .m_name = "syslog", - .m_size = 0, + .m_size = sizeof(_syslog_state), .m_methods = syslog_methods, .m_slots = syslog_slots, + .m_traverse = _syslog_traverse, + .m_clear = _syslog_clear, + .m_free = _syslog_free, }; PyMODINIT_FUNC From 8beb461586fd6cd0e96bccb05368a8ede5ae9f47 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 23:01:29 +0900 Subject: [PATCH 02/23] Address code review --- Modules/syslogmodule.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index a2a216e784d5c5..cd3632d79cf053 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -409,8 +409,11 @@ static int _syslog_clear(PyObject *module) { _syslog_state *state = get_syslog_state(module); - Py_CLEAR(state->S_ident_o); - state->S_log_open = 0; + if (state->S_log_open) { + closelog(); + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; + } return 0; } From d8acc8bde967f2aa9d1dbff17c809684d082bbd9 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 23:41:50 +0900 Subject: [PATCH 03/23] Remove logic to check the openlog status while calling syslog.syslog --- Modules/syslogmodule.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index cd3632d79cf053..ea4dd9ee997445 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -203,14 +203,11 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); - /* if log is not opened, open it now */ - if (!state->S_log_open) { - PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); - if (openlog_ret == NULL) { - return NULL; - } - Py_DECREF(openlog_ret); + PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); + if (openlog_ret == NULL) { + return NULL; } + Py_DECREF(openlog_ret); /* Incref ident, because it can be decrefed if syslog.openlog() is * called when the GIL is released. From 11d9228f67a0f10b5ee43571f8cf98f8a6574612 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 00:17:33 +0900 Subject: [PATCH 04/23] Do not call openlog while calling syslog --- Modules/syslogmodule.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index ea4dd9ee997445..1c13b6cce7a18e 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -203,17 +203,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); - PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); - if (openlog_ret == NULL) { - return NULL; - } - Py_DECREF(openlog_ret); - - /* Incref ident, because it can be decrefed if syslog.openlog() is - * called when the GIL is released. - */ - PyObject *ident = state->S_ident_o; - Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -222,7 +211,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - Py_XDECREF(ident); + state->S_log_open = 1; Py_RETURN_NONE; } From e7408a874ecb5a3a986f3ff9a10128e9bf064593 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 00:36:33 +0900 Subject: [PATCH 05/23] Fix test_audit --- Lib/test/test_audit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 50f78f2a6b8a46..b9c401cc12a81d 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -216,7 +216,6 @@ def test_syslog(self): ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), ('syslog.closelog', '', ''), ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), - ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), ('syslog.closelog', '', '')] From 69ac18a8e583c1874b389228c51c857a3ad0c318 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 12:26:54 +0900 Subject: [PATCH 06/23] nit --- Modules/syslogmodule.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 1c13b6cce7a18e..fbb9fac44b4aca 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -233,9 +233,12 @@ syslog_closelog_impl(PyObject *module) _syslog_state *state = get_syslog_state(module); if (state->S_log_open) { closelog(); - Py_CLEAR(state->S_ident_o); state->S_log_open = 0; } + + if (state->S_ident_o != NULL) { + Py_CLEAR(state->S_ident_o); + } Py_RETURN_NONE; } @@ -397,9 +400,12 @@ _syslog_clear(PyObject *module) _syslog_state *state = get_syslog_state(module); if (state->S_log_open) { closelog(); - Py_CLEAR(state->S_ident_o); state->S_log_open = 0; } + + if (state->S_ident_o != NULL) { + Py_CLEAR(state->S_ident_o); + } return 0; } From 3a784f64838aaadb61ed3ae46908a41649d71910 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 7 Nov 2022 00:18:12 +0900 Subject: [PATCH 07/23] Address code review --- Modules/syslogmodule.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index fbb9fac44b4aca..8e9ccd24114357 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -236,9 +236,7 @@ syslog_closelog_impl(PyObject *module) state->S_log_open = 0; } - if (state->S_ident_o != NULL) { - Py_CLEAR(state->S_ident_o); - } + Py_CLEAR(state->S_ident_o); Py_RETURN_NONE; } @@ -403,9 +401,7 @@ _syslog_clear(PyObject *module) state->S_log_open = 0; } - if (state->S_ident_o != NULL) { - Py_CLEAR(state->S_ident_o); - } + Py_CLEAR(state->S_ident_o); return 0; } From f5cf63a22fb8f8753dab28c1f2da5489c320aabb Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 7 Nov 2022 01:02:23 +0900 Subject: [PATCH 08/23] nit --- Modules/syslogmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 8e9ccd24114357..abefdfd7375cc6 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -408,7 +408,7 @@ _syslog_clear(PyObject *module) static void _syslog_free(void *module) { - _syslog_clear((PyObject *)module); + (void)_syslog_clear((PyObject *)module); } static PyModuleDef_Slot syslog_slots[] = { From fc8582720bba5b3e865fa783939efc7e242fcd76 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:33:27 +0900 Subject: [PATCH 09/23] Address code review --- Modules/syslogmodule.c | 54 +++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index abefdfd7375cc6..e7f73934603568 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -62,10 +62,22 @@ module syslog #include "clinic/syslogmodule.c.h" typedef struct { - PyObject *S_ident_o; /* identifier, held by openlog() */ - char S_log_open; + PyObject *ident_o; /* identifier, held by openlog() */ + char log_open; /* flag for checking whether the openlog() is already called. */ } _syslog_state; + +static inline int is_main_interpreter() +{ + PyInterpreterState *main_interp = PyInterpreterState_Main(); + PyThreadState *tstate = PyThreadState_GET(); + PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); + if (current_interp == main_interp) { + return 0; + } + return -1; +} + static inline _syslog_state* get_syslog_state(PyObject *module) { @@ -143,6 +155,11 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, long facility) /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/ { + if (is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + return NULL; + } + const char *ident_str = NULL; if (ident) { @@ -171,8 +188,8 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, openlog(ident_str, logopt, facility); _syslog_state *state = get_syslog_state(module); - state->S_log_open = 1; - Py_XSETREF(state->S_ident_o, ident); + state->log_open = 1; + Py_XSETREF(state->ident_o, ident); Py_RETURN_NONE; } @@ -203,6 +220,10 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); + if (state->log_open != 1 && is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter."); + return NULL; + } #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -211,7 +232,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - state->S_log_open = 1; + state->log_open = 1; Py_RETURN_NONE; } @@ -226,17 +247,22 @@ static PyObject * syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { + if (is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + return NULL; + } + if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } _syslog_state *state = get_syslog_state(module); - if (state->S_log_open) { + if (state->log_open) { closelog(); - state->S_log_open = 0; + state->log_open = 0; } - Py_CLEAR(state->S_ident_o); + Py_CLEAR(state->ident_o); Py_RETURN_NONE; } @@ -316,8 +342,8 @@ syslog_exec(PyObject *module) } while (0) _syslog_state *state = get_syslog_state(module); - state->S_ident_o = NULL; - state->S_log_open = 0; + state->ident_o = NULL; + state->log_open = 0; /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); @@ -388,7 +414,7 @@ static int _syslog_traverse(PyObject *module, visitproc visit, void *arg) { _syslog_state *state = get_syslog_state(module); - Py_VISIT(state->S_ident_o); + Py_VISIT(state->ident_o); return 0; } @@ -396,12 +422,12 @@ static int _syslog_clear(PyObject *module) { _syslog_state *state = get_syslog_state(module); - if (state->S_log_open) { + if (state->log_open) { closelog(); - state->S_log_open = 0; + state->log_open = 0; } - Py_CLEAR(state->S_ident_o); + Py_CLEAR(state->ident_o); return 0; } From f40d953dc658fa4c909a3f73d38734f6c19e969d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:47:29 +0900 Subject: [PATCH 10/23] Add test --- Lib/test/test_syslog.py | 47 +++++++++++++++++++++++++++++++++++++++++ Modules/syslogmodule.c | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 2125ec58d87e03..746434c48b6725 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -5,6 +5,7 @@ import threading import time import unittest +from textwrap import dedent # XXX(nnorwitz): This test sucks. I don't know of a platform independent way # to verify that the messages were really logged. @@ -78,6 +79,52 @@ def logger(): finally: sys.setswitchinterval(orig_si) + def test_subinterpreter_syslog(self): + code = dedent(''' + import syslog + catch_error = False + try: + syslog.syslog('foo') + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + def test_subinterpreter_openlog(self): + code = dedent(''' + import syslog + catch_error = False + try: + syslog.openlog() + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + def test_subinterpreter_closelog(self): + syslog.openlog('python') + code = dedent(''' + import syslog + catch_error = False + try: + syslog.closelog() + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + syslog.closelog() + + + if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index e7f73934603568..ec339ea3f33438 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -248,7 +248,7 @@ syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { if (is_main_interpreter() < 0) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); return NULL; } From 35bbac240ca7d5f90fd1f57b557e5bcef49b9696 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:48:52 +0900 Subject: [PATCH 11/23] nit --- Modules/syslogmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index ec339ea3f33438..7bcdd454f429be 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -67,7 +67,8 @@ typedef struct { } _syslog_state; -static inline int is_main_interpreter() +static inline int +is_main_interpreter() { PyInterpreterState *main_interp = PyInterpreterState_Main(); PyThreadState *tstate = PyThreadState_GET(); From 525a32b55ed03af6d191f2a0cd638b9d79c16b7b Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:00:32 +0900 Subject: [PATCH 12/23] Address code review --- Lib/test/test_audit.py | 1 + Lib/test/test_syslog.py | 48 ++++++++++++--------- Modules/syslogmodule.c | 93 +++++++++++++---------------------------- 3 files changed, 59 insertions(+), 83 deletions(-) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index b9c401cc12a81d..50f78f2a6b8a46 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -216,6 +216,7 @@ def test_syslog(self): ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), ('syslog.closelog', '', ''), ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), + ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), ('syslog.closelog', '', '')] diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 746434c48b6725..73c89a7c6fb299 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -80,29 +80,41 @@ def logger(): sys.setswitchinterval(orig_si) def test_subinterpreter_syslog(self): - code = dedent(''' - import syslog - catch_error = False - try: - syslog.syslog('foo') - except RuntimeError: - catch_error = True + # syslog.syslog() is not allowed in subinterpreters, but only if + # syslog.openlog() hasn't been called in the main interpreter yet. + with self.subTest('before openlog()'): + code = dedent(''' + import syslog + caught_error = False + try: + syslog.syslog('foo') + except RuntimeError: + caught_error = True + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) - assert(catch_error == True) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) + syslog.openlog() + with self.subTest('after openlog()'): + code = dedent(''' + import syslog + syslog.syslog('foo') + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + syslog.closelog() def test_subinterpreter_openlog(self): code = dedent(''' import syslog - catch_error = False + caught_error = False try: syslog.openlog() except RuntimeError: - catch_error = True + caught_error = True - assert(catch_error == True) + assert(caught_error) ''') res = support.run_in_subinterp(code) self.assertEqual(res, 0) @@ -111,20 +123,18 @@ def test_subinterpreter_closelog(self): syslog.openlog('python') code = dedent(''' import syslog - catch_error = False + caught_error = False try: syslog.closelog() except RuntimeError: - catch_error = True + caught_error = True - assert(catch_error == True) + assert(caught_error) ''') res = support.run_in_subinterp(code) self.assertEqual(res, 0) syslog.closelog() - - if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 7bcdd454f429be..86107e730bb2e9 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -61,11 +61,10 @@ module syslog #include "clinic/syslogmodule.c.h" -typedef struct { - PyObject *ident_o; /* identifier, held by openlog() */ - char log_open; /* flag for checking whether the openlog() is already called. */ -} _syslog_state; - +/* 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 inline int is_main_interpreter() @@ -74,17 +73,9 @@ is_main_interpreter() PyThreadState *tstate = PyThreadState_GET(); PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); if (current_interp == main_interp) { - return 0; + return 1; } - return -1; -} - -static inline _syslog_state* -get_syslog_state(PyObject *module) -{ - void *state = PyModule_GetState(module); - assert(state != NULL); - return (_syslog_state *)state; + return 0; } static PyObject * @@ -156,7 +147,9 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, long facility) /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/ { - if (is_main_interpreter() < 0) { + // Since the sys.openlog changes the process level state of syslog library, + // this operation is only allowed for the main interpreter. + if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); return NULL; } @@ -188,9 +181,8 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, } openlog(ident_str, logopt, facility); - _syslog_state *state = get_syslog_state(module); - state->log_open = 1; - Py_XSETREF(state->ident_o, ident); + S_log_open = 1; + Py_XSETREF(S_ident_o, ident); Py_RETURN_NONE; } @@ -220,10 +212,16 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } - _syslog_state *state = get_syslog_state(module); - if (state->log_open != 1 && is_main_interpreter() < 0) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter."); - return NULL; + if (!S_log_open) { + if (!is_main_interpreter()) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); + return NULL; + } + PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); + if (openlog_ret == NULL) { + return NULL; + } + Py_DECREF(openlog_ret); } #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe @@ -233,7 +231,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - state->log_open = 1; + S_log_open = 1; Py_RETURN_NONE; } @@ -248,7 +246,9 @@ static PyObject * syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { - if (is_main_interpreter() < 0) { + // Since the sys.closelog changes the process level state of syslog library, + // this operation is only allowed for the main interpreter. + if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); return NULL; } @@ -257,13 +257,12 @@ syslog_closelog_impl(PyObject *module) return NULL; } - _syslog_state *state = get_syslog_state(module); - if (state->log_open) { + if (S_log_open) { closelog(); - state->log_open = 0; + S_log_open = 0; + Py_CLEAR(S_ident_o); } - Py_CLEAR(state->ident_o); Py_RETURN_NONE; } @@ -342,10 +341,6 @@ syslog_exec(PyObject *module) } \ } while (0) - _syslog_state *state = get_syslog_state(module); - state->ident_o = NULL; - state->log_open = 0; - /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); @@ -411,33 +406,6 @@ syslog_exec(PyObject *module) return 0; } -static int -_syslog_traverse(PyObject *module, visitproc visit, void *arg) -{ - _syslog_state *state = get_syslog_state(module); - Py_VISIT(state->ident_o); - return 0; -} - -static int -_syslog_clear(PyObject *module) -{ - _syslog_state *state = get_syslog_state(module); - if (state->log_open) { - closelog(); - state->log_open = 0; - } - - Py_CLEAR(state->ident_o); - return 0; -} - -static void -_syslog_free(void *module) -{ - (void)_syslog_clear((PyObject *)module); -} - static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, {0, NULL} @@ -448,12 +416,9 @@ static PyModuleDef_Slot syslog_slots[] = { static struct PyModuleDef syslogmodule = { PyModuleDef_HEAD_INIT, .m_name = "syslog", - .m_size = sizeof(_syslog_state), + .m_size = 0, .m_methods = syslog_methods, .m_slots = syslog_slots, - .m_traverse = _syslog_traverse, - .m_clear = _syslog_clear, - .m_free = _syslog_free, }; PyMODINIT_FUNC From 741baf05f8eed8e6a21997d930768a3e7508e0d1 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:02:58 +0900 Subject: [PATCH 13/23] Update NEWS.d --- .../2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst index 0eab0cac402fd0..e93ae4e7b127d1 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst @@ -1 +1 @@ -Port :mod:`syslog` to use module state. Patch by Dong-hee Na. +Allow some features of :mod:`syslog` to the main interpreter only. Patch by Dong-hee Na. From 779a3d22e2990f23fa694f7b0dc8dabe4b4a932b Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:04:24 +0900 Subject: [PATCH 14/23] nit --- Modules/syslogmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 86107e730bb2e9..60d220fcf35b36 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -340,7 +340,6 @@ syslog_exec(PyObject *module) return -1; \ } \ } while (0) - /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); From 557578f85b2082256b13dbf6499d98cb8f3f45d1 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:07:48 +0900 Subject: [PATCH 15/23] Revert some logic --- Modules/syslogmodule.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 60d220fcf35b36..e26a2b44551276 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -223,6 +223,12 @@ 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 = S_ident_o; + Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -231,7 +237,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - S_log_open = 1; + Py_XDECREF(ident); Py_RETURN_NONE; } From 01334e8e962d80ecf45a425aabae88d36d1a8519 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:09:19 +0900 Subject: [PATCH 16/23] nit --- Modules/syslogmodule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index e26a2b44551276..da0752d515b2e7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -212,6 +212,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } + /* if log is not opened, open it now */ if (!S_log_open) { if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); @@ -262,13 +263,11 @@ syslog_closelog_impl(PyObject *module) if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } - if (S_log_open) { closelog(); - S_log_open = 0; Py_CLEAR(S_ident_o); + S_log_open = 0; } - Py_RETURN_NONE; } From 4ad2b8f173259a73ae42e1e321d9e2e49118a3ed Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 14 Nov 2022 20:49:07 +0900 Subject: [PATCH 17/23] Address code review --- Modules/syslogmodule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index da0752d515b2e7..85c2827b375aa7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -67,7 +67,7 @@ static PyObject *S_ident_o = NULL; // identifier, held by openlog() static char S_log_open = 0; static inline int -is_main_interpreter() +is_main_interpreter(void) { PyInterpreterState *main_interp = PyInterpreterState_Main(); PyThreadState *tstate = PyThreadState_GET(); @@ -150,7 +150,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, // Since the sys.openlog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can not use syslog.openlog"); return NULL; } @@ -215,7 +215,8 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, /* if log is not opened, open it now */ if (!S_log_open) { if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog " + "until the syslog is opened by the main interpreter"); return NULL; } PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); @@ -256,7 +257,7 @@ syslog_closelog_impl(PyObject *module) // Since the sys.closelog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can not use syslog.closelog"); return NULL; } From 696196d8e138d28a4440767f10b934fc3fa56387 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 16 Nov 2022 12:59:21 +0900 Subject: [PATCH 18/23] Update Lib/test/test_syslog.py Co-authored-by: Eric Snow --- Lib/test/test_syslog.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 73c89a7c6fb299..4beeed4c58f6ac 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -96,14 +96,16 @@ def test_subinterpreter_syslog(self): self.assertEqual(res, 0) syslog.openlog() - with self.subTest('after openlog()'): - code = dedent(''' - import syslog - syslog.syslog('foo') - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) - syslog.closelog() + try: + with self.subTest('after openlog()'): + code = dedent(''' + import syslog + syslog.syslog('foo') + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() def test_subinterpreter_openlog(self): code = dedent(''' From 5eeade569d87628f65fc8c5dfc9bfe6ee0ed555e Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 16 Nov 2022 13:05:09 +0900 Subject: [PATCH 19/23] Address code review --- Lib/test/test_syslog.py | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 4beeed4c58f6ac..54db80fa9df1af 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -108,34 +108,39 @@ def test_subinterpreter_syslog(self): syslog.closelog() def test_subinterpreter_openlog(self): - code = dedent(''' - import syslog - caught_error = False - try: - syslog.openlog() - except RuntimeError: - caught_error = True - - assert(caught_error) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) + try: + code = dedent(''' + import syslog + caught_error = False + try: + syslog.openlog() + except RuntimeError: + caught_error = True + + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() def test_subinterpreter_closelog(self): syslog.openlog('python') - code = dedent(''' - import syslog - caught_error = False - try: - syslog.closelog() - except RuntimeError: - caught_error = True - - assert(caught_error) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) - syslog.closelog() + try: + code = dedent(''' + import syslog + caught_error = False + try: + syslog.closelog() + except RuntimeError: + caught_error = True + + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() if __name__ == "__main__": From fb81c1eb81f2a2de720285ee5c90d92ec5d94963 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 10:15:23 +0900 Subject: [PATCH 20/23] Address code review --- Modules/syslogmodule.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 85c2827b375aa7..97f761d253d4f7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -69,13 +69,7 @@ static char S_log_open = 0; static inline int is_main_interpreter(void) { - PyInterpreterState *main_interp = PyInterpreterState_Main(); - PyThreadState *tstate = PyThreadState_GET(); - PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); - if (current_interp == main_interp) { - return 1; - } - return 0; + return (PyInterpreterState_Get() == PyInterpreterState_Main()); } static PyObject * @@ -150,7 +144,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, // Since the sys.openlog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "subinterpreter can not use syslog.openlog"); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()"); return NULL; } @@ -215,7 +209,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 (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog " + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() " "until the syslog is opened by the main interpreter"); return NULL; } @@ -257,7 +251,7 @@ syslog_closelog_impl(PyObject *module) // Since the sys.closelog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can not use syslog.closelog"); + PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()"); return NULL; } From 140366b1861aef326d5162ecfbc69193b83a6c15 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 21:41:54 +0900 Subject: [PATCH 21/23] Update documentations --- Doc/library/syslog.rst | 12 ++++++++++++ Doc/whatsnew/3.12.rst | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst index 766ff57cc66d69..e8440aeb72ec99 100644 --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -40,6 +40,10 @@ The module defines the following functions: it wasn't called prior to the call to :func:`syslog`, deferring to the syslog implementation to call ``openlog()``. + .. versionchanged:: 3.12 + Subinterpreters are allowed to call only if the main interpreter already called :func:`openlog`. + If not, it will raise :exc:`RuntimeError`. + .. function:: openlog([ident[, logoption[, facility]]]) @@ -60,6 +64,10 @@ The module defines the following functions: In previous versions, keyword arguments were not allowed, and *ident* was required. + .. versionchanged:: 3.12 + Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` + if subinterpreters call :func:`openlog`. + .. function:: closelog() @@ -72,6 +80,10 @@ The module defines the following functions: .. audit-event:: syslog.closelog "" syslog.closelog + .. versionchanged:: 3.12 + Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` + if subinterpreters call :func:`closelog`. + .. function:: setlogmask(maskpri) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ead2a9e718a9e2..861d044404a279 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -295,6 +295,13 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +syslog +------ + +* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. + :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. + (Contributed by Dong-hee Na in :gh:`99127`.) + Optimizations ============= From c961709f5b780ab1b0014eead1b3f02d59f44235 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 23:30:29 +0900 Subject: [PATCH 22/23] Address code review --- Doc/whatsnew/3.12.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 861d044404a279..bc08ccf52ac830 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -295,13 +295,6 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) -syslog ------- - -* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. - :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. - (Contributed by Dong-hee Na in :gh:`99127`.) - Optimizations ============= @@ -656,6 +649,10 @@ Changes in the Python API :class:`bytes` type is accepted for bytes strings. (Contributed by Victor Stinner in :gh:`98393`.) +* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. + :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. + (Contributed by Dong-hee Na in :gh:`99127`.) + Build Changes ============= From e8dce888766f52834b1d6fc5b943a58bdf7482af Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 18 Nov 2022 13:58:33 +0900 Subject: [PATCH 23/23] Apply suggestions from code review Co-authored-by: Eric Snow --- Doc/library/syslog.rst | 21 +++++++++++++++------ Doc/whatsnew/3.12.rst | 9 +++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst index e8440aeb72ec99..f29ef03267b1ba 100644 --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -41,8 +41,11 @@ The module defines the following functions: implementation to call ``openlog()``. .. versionchanged:: 3.12 - Subinterpreters are allowed to call only if the main interpreter already called :func:`openlog`. - If not, it will raise :exc:`RuntimeError`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + :func:`openlog` must be called in the main interpreter before :func:`syslog` may be used + in a subinterpreter. Otherwise it will raise :exc:`RuntimeError`. .. function:: openlog([ident[, logoption[, facility]]]) @@ -65,8 +68,11 @@ The module defines the following functions: required. .. versionchanged:: 3.12 - Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` - if subinterpreters call :func:`openlog`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + This may only be called in the main interpreter. + It will raise :exc:`RuntimeError` if called in a subinterpreter. .. function:: closelog() @@ -81,8 +87,11 @@ The module defines the following functions: .. audit-event:: syslog.closelog "" syslog.closelog .. versionchanged:: 3.12 - Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` - if subinterpreters call :func:`closelog`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + This may only be called in the main interpreter. + It will raise :exc:`RuntimeError` if called in a subinterpreter. .. function:: setlogmask(maskpri) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bc08ccf52ac830..b3916956158b40 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -649,8 +649,13 @@ Changes in the Python API :class:`bytes` type is accepted for bytes strings. (Contributed by Victor Stinner in :gh:`98393`.) -* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. - :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. +* :func:`syslog.openlog` and :func:`syslog.closelog` now fail if used in subinterpreters. + :func:`syslog.syslog` may still be used in subinterpreters, + but now only if :func:`syslog.openlog` has already been called in the main interpreter. + These new restrictions do not apply to the main interpreter, + so only a very small set of users might be affected. + This change helps with interpreter isolation. Furthermore, :mod:`syslog` is a wrapper + around process-global resources, which are best managed from the main interpreter. (Contributed by Dong-hee Na in :gh:`99127`.) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy