[3.8] bpo-43439: Add audit hooks for gc functions (GH-24794). (GH-24810) · python/cpython@a6d0182

File tree

5 files changed

lines changed

  • Misc/NEWS.d/next/Security

5 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -72,6 +72,8 @@ The :mod:`gc` module provides the following functions:

7272

.. versionchanged:: 3.8

7373

New *generation* parameter.

7474
75+

.. audit-event:: gc.get_objects generation gc.get_objects

76+
7577

.. function:: get_stats()

7678
7779

Return a list of three per-generation dictionaries containing collection

@@ -141,6 +143,8 @@ The :mod:`gc` module provides the following functions:

141143

invalid state. Avoid using :func:`get_referrers` for any purpose other than

142144

debugging.

143145
146+

.. audit-event:: gc.get_referrers objs gc.get_referrers

147+
144148
145149

.. function:: get_referents(*objs)

146150

@@ -152,6 +156,7 @@ The :mod:`gc` module provides the following functions:

152156

be involved in a cycle. So, for example, if an integer is directly reachable

153157

from an argument, that integer object may or may not appear in the result list.

154158
159+

.. audit-event:: gc.get_referents objs gc.get_referents

155160
156161

.. function:: is_tracked(obj)

157162
Original file line numberDiff line numberDiff line change

@@ -323,6 +323,24 @@ def hook(event, args):

323323

sock.close()

324324
325325
326+

def test_gc():

327+

import gc

328+
329+

def hook(event, args):

330+

if event.startswith("gc."):

331+

print(event, *args)

332+
333+

sys.addaudithook(hook)

334+
335+

gc.get_objects(generation=1)

336+
337+

x = object()

338+

y = [x]

339+
340+

gc.get_referrers(x)

341+

gc.get_referents(y)

342+
343+
326344

if __name__ == "__main__":

327345

from test.support import suppress_msvcrt_asserts

328346
Original file line numberDiff line numberDiff line change

@@ -115,5 +115,18 @@ def test_socket(self):

115115

self.assertEqual(events[2][0], "socket.bind")

116116

self.assertTrue(events[2][2].endswith("('127.0.0.1', 8080)"))

117117
118+

def test_gc(self):

119+

returncode, events, stderr = self.run_python("test_gc")

120+

if returncode:

121+

self.fail(stderr)

122+
123+

if support.verbose:

124+

print(*events, sep='\n')

125+

self.assertEqual(

126+

[event[0] for event in events],

127+

["gc.get_objects", "gc.get_referrers", "gc.get_referents"]

128+

)

129+
130+
118131

if __name__ == "__main__":

119132

unittest.main()

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,2 @@

1+

Add audit hooks for :func:`gc.get_objects`, :func:`gc.get_referrers` and

2+

:func:`gc.get_referents`. Patch by Pablo Galindo.

Original file line numberDiff line numberDiff line change

@@ -1480,6 +1480,10 @@ static PyObject *

14801480

gc_get_referrers(PyObject *self, PyObject *args)

14811481

{

14821482

int i;

1483+

if (PySys_Audit("gc.get_referrers", "O", args) < 0) {

1484+

return NULL;

1485+

}

1486+
14831487

PyObject *result = PyList_New(0);

14841488

if (!result) return NULL;

14851489

@@ -1508,6 +1512,9 @@ static PyObject *

15081512

gc_get_referents(PyObject *self, PyObject *args)

15091513

{

15101514

Py_ssize_t i;

1515+

if (PySys_Audit("gc.get_referents", "O", args) < 0) {

1516+

return NULL;

1517+

}

15111518

PyObject *result = PyList_New(0);

15121519
15131520

if (result == NULL)

@@ -1549,6 +1556,10 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation)

15491556

PyObject* result;

15501557

struct _gc_runtime_state *state = &_PyRuntime.gc;

15511558
1559+

if (PySys_Audit("gc.get_objects", "n", generation) < 0) {

1560+

return NULL;

1561+

}

1562+
15521563

result = PyList_New(0);

15531564

if (result == NULL) {

15541565

return NULL;