Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-99127: Allow some features of syslog to the main interpreter only #99128

Merged
merged 23 commits into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions Lib/test/test_syslog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -78,6 +79,69 @@ def logger():
finally:
sys.setswitchinterval(orig_si)

def test_subinterpreter_syslog(self):
# 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)

syslog.openlog()
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):
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')
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__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Allow some features of :mod:`syslog` to the main interpreter only. Patch by Dong-hee Na.
35 changes: 33 additions & 2 deletions Modules/syslogmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,22 @@ 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() */
/* 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(void)
{
corona10 marked this conversation as resolved.
Show resolved Hide resolved
PyInterpreterState *main_interp = PyInterpreterState_Main();
PyThreadState *tstate = PyThreadState_GET();
PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate);
if (current_interp == main_interp) {
return 1;
}
return 0;
}

static PyObject *
syslog_get_argv(void)
Expand Down Expand Up @@ -135,6 +147,13 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt,
long facility)
/*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/
{
// 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");
corona10 marked this conversation as resolved.
Show resolved Hide resolved
return NULL;
}

const char *ident_str = NULL;

if (ident) {
Expand Down Expand Up @@ -195,6 +214,11 @@ 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 "
corona10 marked this conversation as resolved.
Show resolved Hide resolved
"until the syslog is opened by the main interpreter");
return NULL;
}
PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER);
if (openlog_ret == NULL) {
return NULL;
Expand Down Expand Up @@ -230,6 +254,13 @@ static PyObject *
syslog_closelog_impl(PyObject *module)
/*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/
{
// 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");
corona10 marked this conversation as resolved.
Show resolved Hide resolved
return NULL;
}

if (PySys_Audit("syslog.closelog", NULL) < 0) {
return NULL;
}
Expand Down