]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-41162: Clear audit hooks later during finalization (GH-21222)
authorKonge <zkonge@outlook.com>
Fri, 3 Jul 2020 21:06:46 +0000 (05:06 +0800)
committerGitHub <noreply@github.com>
Fri, 3 Jul 2020 21:06:46 +0000 (22:06 +0100)
Lib/test/audit-tests.py
Lib/test/test_audit.py
Misc/NEWS.d/next/Security/2020-07-03-20-41-29.bpo-41162.tb8pVj.rst [new file with mode: 0644]
Programs/_testembed.c
Python/pylifecycle.c

index a58395b068b3955f69ff50cd42d8febd65f83b9d..ee6fc93351b753392e317e30cd8c1d85085648fc 100644 (file)
@@ -44,28 +44,6 @@ class TestHook:
             raise self.exc_type("saw event " + event)
 
 
-class TestFinalizeHook:
-    """Used in the test_finalize_hooks function to ensure that hooks
-    are correctly cleaned up, that they are notified about the cleanup,
-    and are unable to prevent it.
-    """
-
-    def __init__(self):
-        print("Created", id(self), file=sys.stdout, flush=True)
-
-    def __call__(self, event, args):
-        # Avoid recursion when we call id() below
-        if event == "builtins.id":
-            return
-
-        print(event, id(self), file=sys.stdout, flush=True)
-
-        if event == "cpython._PySys_ClearAuditHooks":
-            raise RuntimeError("Should be ignored")
-        elif event == "cpython.PyInterpreterState_Clear":
-            raise RuntimeError("Should be ignored")
-
-
 # Simple helpers, since we are not in unittest here
 def assertEqual(x, y):
     if x != y:
@@ -128,10 +106,6 @@ def test_block_add_hook_baseexception():
                 pass
 
 
-def test_finalize_hooks():
-    sys.addaudithook(TestFinalizeHook())
-
-
 def test_pickle():
     import pickle
 
index f405c6923979ca16d85c90b5e01879deac47fecb..f79edbc4bd0d9fc6493be10d44a41a9e1c153e9c 100644 (file)
@@ -51,22 +51,6 @@ class AuditTest(unittest.TestCase):
     def test_block_add_hook_baseexception(self):
         self.do_test("test_block_add_hook_baseexception")
 
-    def test_finalize_hooks(self):
-        returncode, events, stderr = self.run_python("test_finalize_hooks")
-        if stderr:
-            print(stderr, file=sys.stderr)
-        if returncode:
-            self.fail(stderr)
-
-        firstId = events[0][2]
-        self.assertSequenceEqual(
-            [
-                ("Created", " ", firstId),
-                ("cpython._PySys_ClearAuditHooks", " ", firstId),
-            ],
-            events,
-        )
-
     def test_pickle(self):
         support.import_module("pickle")
 
diff --git a/Misc/NEWS.d/next/Security/2020-07-03-20-41-29.bpo-41162.tb8pVj.rst b/Misc/NEWS.d/next/Security/2020-07-03-20-41-29.bpo-41162.tb8pVj.rst
new file mode 100644 (file)
index 0000000..f0333ac
--- /dev/null
@@ -0,0 +1 @@
+Audit hooks are now cleared later during finalization to avoid missing events.
\ No newline at end of file
index b60d70be5f71e69f2e29d8f9ef02e1e2f4109c73..5aad16a6f7c47d1273f65346a76bfa0b2662ef91 100644 (file)
@@ -1112,8 +1112,11 @@ static int test_open_code_hook(void)
     return result;
 }
 
+static int _audit_hook_clear_count = 0;
+
 static int _audit_hook(const char *event, PyObject *args, void *userdata)
 {
+    assert(args && PyTuple_CheckExact(args));
     if (strcmp(event, "_testembed.raise") == 0) {
         PyErr_SetString(PyExc_RuntimeError, "Intentional error");
         return -1;
@@ -1122,6 +1125,8 @@ static int _audit_hook(const char *event, PyObject *args, void *userdata)
             return -1;
         }
         return 0;
+    } else if (strcmp(event, "cpython._PySys_ClearAuditHooks") == 0) {
+        _audit_hook_clear_count += 1;
     }
     return 0;
 }
@@ -1167,6 +1172,9 @@ static int test_audit(void)
 {
     int result = _test_audit(42);
     Py_Finalize();
+    if (_audit_hook_clear_count != 1) {
+        return 0x1000 | _audit_hook_clear_count;
+    }
     return result;
 }
 
index 3ce2c41ef1ff69fb54573d1c7ca80793d11a85a1..2d219a4a3a8b0db5a9c4fd8497565491aa413dd2 100644 (file)
@@ -1291,6 +1291,13 @@ finalize_interp_clear(PyThreadState *tstate)
         _PyGC_CollectNoFail();
     }
 
+    /* Clear all loghooks */
+    /* Both _PySys_Audit function and users still need PyObject, such as tuple.
+       Call _PySys_ClearAuditHooks when PyObject available. */
+    if (is_main_interp) {
+        _PySys_ClearAuditHooks(tstate);
+    }
+
     _PyGC_Fini(tstate);
 
     if (is_main_interp) {
@@ -1405,9 +1412,6 @@ Py_FinalizeEx(void)
      */
     _PyGC_CollectIfEnabled();
 
-    /* Clear all loghooks */
-    _PySys_ClearAuditHooks(tstate);
-
     /* Destroy all modules */
     _PyImport_Cleanup(tstate);