Skip to content

Commit 8c837e7

Browse files
committed
Add tests for socket audit hook leak
1 parent bef84d6 commit 8c837e7

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

Lib/test/test_socket.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from unittest import mock
33
from test import support
44
from test.support import (
5-
cpython_only, is_apple, os_helper, refleak_helper, socket_helper, threading_helper
5+
cpython_only, is_apple, os_helper, refleak_helper, script_helper, socket_helper, threading_helper
66
)
77
from test.support.import_helper import ensure_lazy_imports
88
import _thread as thread
@@ -28,6 +28,7 @@
2828
import struct
2929
import sys
3030
import tempfile
31+
import textwrap
3132
import threading
3233
import time
3334
import traceback
@@ -7498,6 +7499,57 @@ def close_fds(fds):
74987499
self.assertEqual(data, str(index).encode())
74997500

75007501

7502+
@support.requires_subprocess()
7503+
@unittest.skipUnless(hasattr(sys, "gettotalrefcount"),
7504+
"requires sys.gettotalrefcount()")
7505+
class AuditHookLeakTests(unittest.TestCase):
7506+
# gh-146245: Reference and buffer may leaks in audit hook's failures path.
7507+
7508+
def test_getaddrinfo_audit_hook_leak(self):
7509+
code = textwrap.dedent("""
7510+
import socket
7511+
import sys
7512+
import gc
7513+
sys.addaudithook(lambda *a: (_ for _ in ()).throw(RuntimeError("audit")))
7514+
gc.collect()
7515+
before = sys.gettotalrefcount()
7516+
for _ in range(100):
7517+
try:
7518+
socket.getaddrinfo(None, 80)
7519+
except RuntimeError:
7520+
pass
7521+
gc.collect()
7522+
after = sys.gettotalrefcount()
7523+
print(after - before)
7524+
""")
7525+
rc, out, err = script_helper.assert_python_ok("-c", code)
7526+
leaked = int(out.strip())
7527+
self.assertLessEqual(leaked, 2, f"Leaked {leaked} references")
7528+
7529+
def test_sendto_audit_hook_leak(self):
7530+
code = textwrap.dedent("""
7531+
import socket
7532+
import sys
7533+
import gc
7534+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
7535+
sys.addaudithook(lambda *a: (_ for _ in ()).throw(RuntimeError("audit")))
7536+
gc.collect()
7537+
before = sys.gettotalrefcount()
7538+
for _ in range(100):
7539+
try:
7540+
s.sendto(bytearray(b"x"), ("127.0.0.1", 80))
7541+
except RuntimeError:
7542+
pass
7543+
gc.collect()
7544+
after = sys.gettotalrefcount()
7545+
s.close()
7546+
print(after - before)
7547+
""")
7548+
rc, out, err = script_helper.assert_python_ok("-c", code)
7549+
leaked = int(out.strip())
7550+
self.assertLessEqual(leaked, 2, f"Leaked {leaked} references")
7551+
7552+
75017553
class FreeThreadingTests(unittest.TestCase):
75027554

75037555
def test_close_detach_race(self):

0 commit comments

Comments
 (0)