From 87330e72690309d6277c448387f11b7171f670cb Mon Sep 17 00:00:00 2001
From: Ronald Oussoren <ronaldoussoren@mac.com>
Date: Sun, 14 Jan 2024 14:51:34 +0100
Subject: [PATCH 1/3] gh-80931: Skip some socket tests while hunting for
 refleaks on macOS

---
 Lib/test/test_socket.py | 76 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 4eb5af99d6674c..9f43a04ee40feb 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -52,6 +52,28 @@
 except ImportError:
     _socket = None
 
+_hunting_for_refleaks = None
+def hunting_for_refleaks():
+    """
+    Return true iff running tests while hunting for refleaks
+    """
+    from test.libregrtest.runtests import RunTests
+    import gc
+
+    global _hunting_for_refleaks
+
+    if _hunting_for_refleaks is None:
+        for value in gc.get_objects():
+            if isinstance(value, RunTests):
+                _hunting_for_refleaks = (value.hunt_refleak is not None)
+                break
+        else:
+            _hunting_for_refleaks = False
+
+    return _hunting_for_refleaks
+
+
+
 def get_cid():
     if fcntl is None:
         return None
@@ -3817,6 +3839,9 @@ def checkTruncatedHeader(self, result, ignoreflags=0):
     def testCmsgTruncNoBufSize(self):
         # Check that no ancillary data is received when no buffer size
         # is specified.
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG)),
                                   # BSD seems to set MSG_CTRUNC only
                                   # if an item has been partially
@@ -3824,26 +3849,44 @@ def testCmsgTruncNoBufSize(self):
                                   ignoreflags=socket.MSG_CTRUNC)
 
     def _testCmsgTruncNoBufSize(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     def testCmsgTrunc0(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         # Check that no ancillary data is received when buffer size is 0.
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 0),
                                   ignoreflags=socket.MSG_CTRUNC)
 
     def _testCmsgTrunc0(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     # Check that no ancillary data is returned for various non-zero
     # (but still too small) buffer sizes.
 
     def testCmsgTrunc1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1))
 
     def _testCmsgTrunc1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     def testCmsgTrunc2Int(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         # The cmsghdr structure has at least three members, two of
         # which are ints, so we still shouldn't see any ancillary
         # data.
@@ -3851,13 +3894,22 @@ def testCmsgTrunc2Int(self):
                                                  SIZEOF_INT * 2))
 
     def _testCmsgTrunc2Int(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     def testCmsgTruncLen0Minus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG),
                                                  socket.CMSG_LEN(0) - 1))
 
     def _testCmsgTruncLen0Minus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     # The following tests try to truncate the control message in the
@@ -3888,29 +3940,53 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0):
         self.checkFDs(fds)
 
     def testCmsgTruncLen0(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0)
 
     def _testCmsgTruncLen0(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(1)
 
     def testCmsgTruncLen0Plus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1)
 
     def _testCmsgTruncLen0Plus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(2)
 
     def testCmsgTruncLen1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT),
                                  maxdata=SIZEOF_INT)
 
     def _testCmsgTruncLen1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(2)
 
     def testCmsgTruncLen2Minus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1,
                                  maxdata=(2 * SIZEOF_INT) - 1)
 
     def _testCmsgTruncLen2Minus1(self):
+        if sys.platform == "darwin" and hunting_for_refleaks():
+            return
+
         self.createAndSendFDs(2)
 
 

From 1fc244379dfe5fb518f14246b5a25a0980335758 Mon Sep 17 00:00:00 2001
From: Ronald Oussoren <ronaldoussoren@mac.com>
Date: Sun, 14 Jan 2024 15:34:25 +0100
Subject: [PATCH 2/3] Cleaner way of annotating test functions using a
 decorator

---
 Lib/test/test_socket.py | 98 ++++++++++++++++++++---------------------
 1 file changed, 47 insertions(+), 51 deletions(-)

diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 9f43a04ee40feb..7904f4c701d4c3 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -73,6 +73,34 @@ def hunting_for_refleaks():
     return _hunting_for_refleaks
 
 
+def skipForRefleakHuntinIf(condition, issueref):
+    if not condition:
+        def decorator(f):
+            f.client_skip = lambda f: f
+            return f
+
+    else:
+        def decorator(f):
+            @contextlib.wraps(f)
+            def wrapper(*args, **kwds):
+                if hunting_for_refleaks():
+                    raise unittest.SkipTest(f"ignore while hunting for refleaks, see {issueref}")
+
+                return f(*args, **kwds)
+
+            def client_skip(f):
+                @contextlib.wraps(f)
+                def wrapper(*args, **kwds):
+                    if hunting_for_refleaks():
+                        return
+
+                    return f(*args, **kwds)
+
+                return wrapper
+            wrapper.client_skip = client_skip
+            return wrapper
+
+    return decorator
 
 def get_cid():
     if fcntl is None:
@@ -3836,32 +3864,27 @@ def checkTruncatedHeader(self, result, ignoreflags=0):
         self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC,
                         ignore=ignoreflags)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTruncNoBufSize(self):
         # Check that no ancillary data is received when no buffer size
         # is specified.
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG)),
                                   # BSD seems to set MSG_CTRUNC only
                                   # if an item has been partially
                                   # received.
                                   ignoreflags=socket.MSG_CTRUNC)
 
+    @testCmsgTruncNoBufSize.client_skip
     def _testCmsgTruncNoBufSize(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTrunc0(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         # Check that no ancillary data is received when buffer size is 0.
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 0),
                                   ignoreflags=socket.MSG_CTRUNC)
 
+    @testCmsgTrunc0.client_skip
     def _testCmsgTrunc0(self):
         if sys.platform == "darwin" and hunting_for_refleaks():
             return
@@ -3871,45 +3894,33 @@ def _testCmsgTrunc0(self):
     # Check that no ancillary data is returned for various non-zero
     # (but still too small) buffer sizes.
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTrunc1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1))
 
+    @testCmsgTrunc1.client_skip
     def _testCmsgTrunc1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTrunc2Int(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         # The cmsghdr structure has at least three members, two of
         # which are ints, so we still shouldn't see any ancillary
         # data.
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG),
                                                  SIZEOF_INT * 2))
 
+    @testCmsgTrunc2Int.client_skip
     def _testCmsgTrunc2Int(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTruncLen0Minus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG),
                                                  socket.CMSG_LEN(0) - 1))
 
+    @testCmsgTruncLen0Minus1.client_skip
     def _testCmsgTruncLen0Minus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
     # The following tests try to truncate the control message in the
@@ -3939,54 +3950,39 @@ def checkTruncatedArray(self, ancbuf, maxdata, mindata=0):
                 len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
         self.checkFDs(fds)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTruncLen0(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0)
 
+    @testCmsgTruncLen0.client_skip
     def _testCmsgTruncLen0(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTruncLen0Plus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1)
 
+    @testCmsgTruncLen0Plus1.client_skip
     def _testCmsgTruncLen0Plus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(2)
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
     def testCmsgTruncLen1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT),
                                  maxdata=SIZEOF_INT)
 
+    @testCmsgTruncLen1.client_skip
     def _testCmsgTruncLen1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(2)
 
-    def testCmsgTruncLen2Minus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
 
+    @skipForRefleakHuntinIf(sys.platform == "darwin", "#80931")
+    def testCmsgTruncLen2Minus1(self):
         self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1,
                                  maxdata=(2 * SIZEOF_INT) - 1)
 
+    @testCmsgTruncLen2Minus1.client_skip
     def _testCmsgTruncLen2Minus1(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(2)
 
 

From 8907efc6b32abc28848ecc93c406777261202d8a Mon Sep 17 00:00:00 2001
From: Ronald Oussoren <ronaldoussoren@mac.com>
Date: Sun, 14 Jan 2024 15:51:18 +0100
Subject: [PATCH 3/3] Integrate the refleak run check into regrtest and
 test.support

---
 Lib/test/libregrtest/refleak.py    |  8 +++++++-
 Lib/test/support/refleak_helper.py |  8 ++++++++
 Lib/test/test_socket.py            | 29 +++--------------------------
 3 files changed, 18 insertions(+), 27 deletions(-)
 create mode 100644 Lib/test/support/refleak_helper.py

diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py
index 5836a8421cb42d..7da16cf721f097 100644
--- a/Lib/test/libregrtest/refleak.py
+++ b/Lib/test/libregrtest/refleak.py
@@ -5,6 +5,7 @@
 
 from test import support
 from test.support import os_helper
+from test.support import refleak_helper
 
 from .runtests import HuntRefleak
 from .utils import clear_caches
@@ -96,7 +97,12 @@ def get_pooled_int(value):
     support.gc_collect()
 
     for i in rep_range:
-        results = test_func()
+        current = refleak_helper._hunting_for_refleaks
+        refleak_helper._hunting_for_refleaks = True
+        try:
+            results = test_func()
+        finally:
+            refleak_helper._hunting_for_refleaks = current
 
         dash_R_cleanup(fs, ps, pic, zdc, abcs)
         support.gc_collect()
diff --git a/Lib/test/support/refleak_helper.py b/Lib/test/support/refleak_helper.py
new file mode 100644
index 00000000000000..2f86c93a1e2e58
--- /dev/null
+++ b/Lib/test/support/refleak_helper.py
@@ -0,0 +1,8 @@
+"""
+Utilities for changing test behaviour while hunting
+for refleaks
+"""
+
+_hunting_for_refleaks = False
+def hunting_for_refleaks():
+    return _hunting_for_refleaks
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 7904f4c701d4c3..231448c75f01db 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -3,6 +3,7 @@
 from test.support import os_helper
 from test.support import socket_helper
 from test.support import threading_helper
+from test.support import refleak_helper
 
 import _thread as thread
 import array
@@ -52,27 +53,6 @@
 except ImportError:
     _socket = None
 
-_hunting_for_refleaks = None
-def hunting_for_refleaks():
-    """
-    Return true iff running tests while hunting for refleaks
-    """
-    from test.libregrtest.runtests import RunTests
-    import gc
-
-    global _hunting_for_refleaks
-
-    if _hunting_for_refleaks is None:
-        for value in gc.get_objects():
-            if isinstance(value, RunTests):
-                _hunting_for_refleaks = (value.hunt_refleak is not None)
-                break
-        else:
-            _hunting_for_refleaks = False
-
-    return _hunting_for_refleaks
-
-
 def skipForRefleakHuntinIf(condition, issueref):
     if not condition:
         def decorator(f):
@@ -83,7 +63,7 @@ def decorator(f):
         def decorator(f):
             @contextlib.wraps(f)
             def wrapper(*args, **kwds):
-                if hunting_for_refleaks():
+                if refleak_helper.hunting_for_refleaks():
                     raise unittest.SkipTest(f"ignore while hunting for refleaks, see {issueref}")
 
                 return f(*args, **kwds)
@@ -91,7 +71,7 @@ def wrapper(*args, **kwds):
             def client_skip(f):
                 @contextlib.wraps(f)
                 def wrapper(*args, **kwds):
-                    if hunting_for_refleaks():
+                    if refleak_helper.hunting_for_refleaks():
                         return
 
                     return f(*args, **kwds)
@@ -3886,9 +3866,6 @@ def testCmsgTrunc0(self):
 
     @testCmsgTrunc0.client_skip
     def _testCmsgTrunc0(self):
-        if sys.platform == "darwin" and hunting_for_refleaks():
-            return
-
         self.createAndSendFDs(1)
 
     # Check that no ancillary data is returned for various non-zero