From 379eac1db087a6c67ee5be8c7fa1b091e3889abc Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Mon, 8 Mar 2021 23:06:19 +0000 Subject: [PATCH 1/2] bpo-43439: Add audit hooks for gc functions --- Doc/library/gc.rst | 5 +++++ Doc/whatsnew/3.10.rst | 5 +++++ Lib/test/audit-tests.py | 18 ++++++++++++++++++ Lib/test/test_audit.py | 14 ++++++++++++++ .../2021-03-08-23-06-07.bpo-43439.5U3lXm.rst | 2 ++ Modules/gcmodule.c | 11 +++++++++++ 6 files changed, 55 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2021-03-08-23-06-07.bpo-43439.5U3lXm.rst diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst index a3d201d5055c8ec..69a1a8313b75931 100644 --- a/Doc/library/gc.rst +++ b/Doc/library/gc.rst @@ -72,6 +72,8 @@ The :mod:`gc` module provides the following functions: .. versionchanged:: 3.8 New *generation* parameter. + .. audit-event:: gc.get_objects generation gc.get_objects + .. function:: get_stats() Return a list of three per-generation dictionaries containing collection @@ -141,6 +143,8 @@ The :mod:`gc` module provides the following functions: invalid state. Avoid using :func:`get_referrers` for any purpose other than debugging. + .. audit-event:: gc.get_referrers objs gc.get_referrers + .. function:: get_referents(*objs) @@ -152,6 +156,7 @@ The :mod:`gc` module provides the following functions: be involved in a cycle. So, for example, if an integer is directly reachable from an argument, that integer object may or may not appear in the result list. + .. audit-event:: gc.get_referents objs gc.get_referents .. function:: is_tracked(obj) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index db71f061f14df45..c0e5e12a28aa755 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -676,6 +676,11 @@ encodings :func:`encodings.normalize_encoding` now ignores non-ASCII characters. (Contributed by Hai Shi in :issue:`39337`.) +gc +-- +Added audit hooks for :func:`gc.get_objects`, :func:`gc.get_referrers` and +:func:`gc.get_referents`. (Contributed by Pablo Galindo in :issue:`43439`.) + glob ---- diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index ee6fc93351b7533..8e66594e52429b6 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -323,6 +323,24 @@ def hook(event, args): sock.close() +def test_gc(): + import gc + + def hook(event, args): + if event.startswith("gc."): + print(event, *args) + + sys.addaudithook(hook) + + gc.get_objects(generation=1) + + x = object() + y = [x] + + gc.get_referrers(x) + gc.get_referents(y) + + if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 4f8d06a3ebcbeeb..b4a8b29e922450d 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -118,5 +118,19 @@ def test_socket(self): self.assertEqual(events[2][0], "socket.bind") self.assertTrue(events[2][2].endswith("('127.0.0.1', 8080)")) + def test_gc(self): + import_helper.import_module("gc") + returncode, events, stderr = self.run_python("test_gc") + if returncode: + self.fail(stderr) + + if support.verbose: + print(*events, sep='\n') + self.assertEqual(events[0][0], "gc.get_objects") + self.assertEqual(events[1][0], "gc.get_referrers") + self.assertEqual(events[2][0], "gc.get_referents") + + + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Security/2021-03-08-23-06-07.bpo-43439.5U3lXm.rst b/Misc/NEWS.d/next/Security/2021-03-08-23-06-07.bpo-43439.5U3lXm.rst new file mode 100644 index 000000000000000..518650303683d21 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2021-03-08-23-06-07.bpo-43439.5U3lXm.rst @@ -0,0 +1,2 @@ +Add audit hooks for :func:`gc.get_objects`, :func:`gc.get_referrers` and +:func:`gc.get_referents`. Patch by Pablo Galindo. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 21f6bd1a9b6d0e1..225da2b20959250 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -1690,6 +1690,10 @@ Return the list of objects that directly refer to any of objs."); static PyObject * gc_get_referrers(PyObject *self, PyObject *args) { + if (PySys_Audit("gc.get_referrers", "O", args) < 0) { + return NULL; + } + PyObject *result = PyList_New(0); if (!result) { return NULL; @@ -1720,6 +1724,9 @@ static PyObject * gc_get_referents(PyObject *self, PyObject *args) { Py_ssize_t i; + if (PySys_Audit("gc.get_referents", "O", args) < 0) { + return NULL; + } PyObject *result = PyList_New(0); if (result == NULL) @@ -1762,6 +1769,10 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation) PyObject* result; GCState *gcstate = &tstate->interp->gc; + if (PySys_Audit("gc.get_objects", "n", generation) < 0) { + return NULL; + } + result = PyList_New(0); if (result == NULL) { return NULL; From d6c47f70fa419d1c4bc23a21f99815d07af56d2b Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 9 Mar 2021 20:20:05 +0000 Subject: [PATCH 2/2] fixup! bpo-43439: Add audit hooks for gc functions --- Doc/whatsnew/3.10.rst | 2 ++ Lib/test/test_audit.py | 9 ++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index c0e5e12a28aa755..814594a0525958f 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -673,11 +673,13 @@ When a module does not define ``__loader__``, fall back to ``__spec__.loader``. encodings --------- + :func:`encodings.normalize_encoding` now ignores non-ASCII characters. (Contributed by Hai Shi in :issue:`39337`.) gc -- + Added audit hooks for :func:`gc.get_objects`, :func:`gc.get_referrers` and :func:`gc.get_referents`. (Contributed by Pablo Galindo in :issue:`43439`.) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index b4a8b29e922450d..58180e147a49a37 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -119,17 +119,16 @@ def test_socket(self): self.assertTrue(events[2][2].endswith("('127.0.0.1', 8080)")) def test_gc(self): - import_helper.import_module("gc") returncode, events, stderr = self.run_python("test_gc") if returncode: self.fail(stderr) if support.verbose: print(*events, sep='\n') - self.assertEqual(events[0][0], "gc.get_objects") - self.assertEqual(events[1][0], "gc.get_referrers") - self.assertEqual(events[2][0], "gc.get_referents") - + self.assertEqual( + [event[0] for event in events], + ["gc.get_objects", "gc.get_referrers", "gc.get_referents"] + ) if __name__ == "__main__":