| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | """This script contains the actual auditing tests.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | It should not be imported directly, but should be run by the test_audit | 
					
						
							|  |  |  | module with arguments identifying each test. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import contextlib | 
					
						
							| 
									
										
										
										
											2021-06-30 17:21:37 +01:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestHook: | 
					
						
							|  |  |  |     """Used in standard hook tests to collect any logged events.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Should be used in a with block to ensure that it has no impact | 
					
						
							|  |  |  |     after the test completes. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, raise_on_events=None, exc_type=RuntimeError): | 
					
						
							|  |  |  |         self.raise_on_events = raise_on_events or () | 
					
						
							|  |  |  |         self.exc_type = exc_type | 
					
						
							|  |  |  |         self.seen = [] | 
					
						
							|  |  |  |         self.closed = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __enter__(self, *a): | 
					
						
							|  |  |  |         sys.addaudithook(self) | 
					
						
							|  |  |  |         return self | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __exit__(self, *a): | 
					
						
							|  |  |  |         self.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def close(self): | 
					
						
							|  |  |  |         self.closed = True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @property | 
					
						
							|  |  |  |     def seen_events(self): | 
					
						
							|  |  |  |         return [i[0] for i in self.seen] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, event, args): | 
					
						
							|  |  |  |         if self.closed: | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         self.seen.append((event, args)) | 
					
						
							|  |  |  |         if event in self.raise_on_events: | 
					
						
							|  |  |  |             raise self.exc_type("saw event " + event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Simple helpers, since we are not in unittest here | 
					
						
							|  |  |  | def assertEqual(x, y): | 
					
						
							|  |  |  |     if x != y: | 
					
						
							|  |  |  |         raise AssertionError(f"{x!r} should equal {y!r}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def assertIn(el, series): | 
					
						
							|  |  |  |     if el not in series: | 
					
						
							|  |  |  |         raise AssertionError(f"{el!r} should be in {series!r}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def assertNotIn(el, series): | 
					
						
							|  |  |  |     if el in series: | 
					
						
							|  |  |  |         raise AssertionError(f"{el!r} should not be in {series!r}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def assertSequenceEqual(x, y): | 
					
						
							|  |  |  |     if len(x) != len(y): | 
					
						
							|  |  |  |         raise AssertionError(f"{x!r} should equal {y!r}") | 
					
						
							|  |  |  |     if any(ix != iy for ix, iy in zip(x, y)): | 
					
						
							|  |  |  |         raise AssertionError(f"{x!r} should equal {y!r}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @contextlib.contextmanager | 
					
						
							|  |  |  | def assertRaises(ex_type): | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         yield | 
					
						
							|  |  |  |         assert False, f"expected {ex_type}" | 
					
						
							|  |  |  |     except BaseException as ex: | 
					
						
							|  |  |  |         if isinstance(ex, AssertionError): | 
					
						
							|  |  |  |             raise | 
					
						
							|  |  |  |         assert type(ex) is ex_type, f"{ex} should be {ex_type}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_basic(): | 
					
						
							|  |  |  |     with TestHook() as hook: | 
					
						
							|  |  |  |         sys.audit("test_event", 1, 2, 3) | 
					
						
							|  |  |  |         assertEqual(hook.seen[0][0], "test_event") | 
					
						
							|  |  |  |         assertEqual(hook.seen[0][1], (1, 2, 3)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_block_add_hook(): | 
					
						
							|  |  |  |     # Raising an exception should prevent a new hook from being added, | 
					
						
							|  |  |  |     # but will not propagate out. | 
					
						
							|  |  |  |     with TestHook(raise_on_events="sys.addaudithook") as hook1: | 
					
						
							|  |  |  |         with TestHook() as hook2: | 
					
						
							|  |  |  |             sys.audit("test_event") | 
					
						
							|  |  |  |             assertIn("test_event", hook1.seen_events) | 
					
						
							|  |  |  |             assertNotIn("test_event", hook2.seen_events) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_block_add_hook_baseexception(): | 
					
						
							|  |  |  |     # Raising BaseException will propagate out when adding a hook | 
					
						
							|  |  |  |     with assertRaises(BaseException): | 
					
						
							|  |  |  |         with TestHook( | 
					
						
							|  |  |  |             raise_on_events="sys.addaudithook", exc_type=BaseException | 
					
						
							|  |  |  |         ) as hook1: | 
					
						
							|  |  |  |             # Adding this next hook should raise BaseException | 
					
						
							|  |  |  |             with TestHook() as hook2: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-30 17:21:37 +01:00
										 |  |  | def test_marshal(): | 
					
						
							|  |  |  |     import marshal | 
					
						
							|  |  |  |     o = ("a", "b", "c", 1, 2, 3) | 
					
						
							|  |  |  |     payload = marshal.dumps(o) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with TestHook() as hook: | 
					
						
							|  |  |  |         assertEqual(o, marshal.loads(marshal.dumps(o))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             with open("test-marshal.bin", "wb") as f: | 
					
						
							|  |  |  |                 marshal.dump(o, f) | 
					
						
							|  |  |  |             with open("test-marshal.bin", "rb") as f: | 
					
						
							|  |  |  |                 assertEqual(o, marshal.load(f)) | 
					
						
							|  |  |  |         finally: | 
					
						
							|  |  |  |             os.unlink("test-marshal.bin") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actual = [(a[0], a[1]) for e, a in hook.seen if e == "marshal.dumps"] | 
					
						
							|  |  |  |     assertSequenceEqual(actual, [(o, marshal.version)] * 2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actual = [a[0] for e, a in hook.seen if e == "marshal.loads"] | 
					
						
							|  |  |  |     assertSequenceEqual(actual, [payload]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actual = [e for e, a in hook.seen if e == "marshal.load"] | 
					
						
							|  |  |  |     assertSequenceEqual(actual, ["marshal.load"]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | def test_pickle(): | 
					
						
							|  |  |  |     import pickle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class PicklePrint: | 
					
						
							|  |  |  |         def __reduce_ex__(self, p): | 
					
						
							|  |  |  |             return str, ("Pwned!",) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     payload_1 = pickle.dumps(PicklePrint()) | 
					
						
							|  |  |  |     payload_2 = pickle.dumps(("a", "b", "c", 1, 2, 3)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Before we add the hook, ensure our malicious pickle loads | 
					
						
							|  |  |  |     assertEqual("Pwned!", pickle.loads(payload_1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with TestHook(raise_on_events="pickle.find_class") as hook: | 
					
						
							|  |  |  |         with assertRaises(RuntimeError): | 
					
						
							|  |  |  |             # With the hook enabled, loading globals is not allowed | 
					
						
							|  |  |  |             pickle.loads(payload_1) | 
					
						
							|  |  |  |         # pickles with no globals are okay | 
					
						
							|  |  |  |         pickle.loads(payload_2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_monkeypatch(): | 
					
						
							|  |  |  |     class A: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class B: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class C(A): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     a = A() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with TestHook() as hook: | 
					
						
							|  |  |  |         # Catch name changes | 
					
						
							|  |  |  |         C.__name__ = "X" | 
					
						
							|  |  |  |         # Catch type changes | 
					
						
							|  |  |  |         C.__bases__ = (B,) | 
					
						
							|  |  |  |         # Ensure bypassing __setattr__ is still caught | 
					
						
							|  |  |  |         type.__dict__["__bases__"].__set__(C, (B,)) | 
					
						
							|  |  |  |         # Catch attribute replacement | 
					
						
							|  |  |  |         C.__init__ = B.__init__ | 
					
						
							|  |  |  |         # Catch attribute addition | 
					
						
							|  |  |  |         C.new_attr = 123 | 
					
						
							|  |  |  |         # Catch class changes | 
					
						
							|  |  |  |         a.__class__ = B | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     actual = [(a[0], a[1]) for e, a in hook.seen if e == "object.__setattr__"] | 
					
						
							|  |  |  |     assertSequenceEqual( | 
					
						
							|  |  |  |         [(C, "__name__"), (C, "__bases__"), (C, "__bases__"), (a, "__class__")], actual | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  | def test_open(testfn): | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  |     # SSLContext.load_dh_params uses _Py_fopen_obj rather than normal open() | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import ssl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         load_dh_params = ssl.create_default_context().load_dh_params | 
					
						
							|  |  |  |     except ImportError: | 
					
						
							|  |  |  |         load_dh_params = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Try a range of "open" functions. | 
					
						
							|  |  |  |     # All of them should fail | 
					
						
							|  |  |  |     with TestHook(raise_on_events={"open"}) as hook: | 
					
						
							|  |  |  |         for fn, *args in [ | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |             (open, testfn, "r"), | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  |             (open, sys.executable, "rb"), | 
					
						
							|  |  |  |             (open, 3, "wb"), | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |             (open, testfn, "w", -1, None, None, None, False, lambda *a: 1), | 
					
						
							|  |  |  |             (load_dh_params, testfn), | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  |         ]: | 
					
						
							|  |  |  |             if not fn: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  |             with assertRaises(RuntimeError): | 
					
						
							| 
									
										
										
										
											2025-03-28 16:28:11 +00:00
										 |  |  |                 try: | 
					
						
							|  |  |  |                     fn(*args) | 
					
						
							|  |  |  |                 except NotImplementedError: | 
					
						
							|  |  |  |                     if fn == load_dh_params: | 
					
						
							|  |  |  |                         # Not callable in some builds | 
					
						
							|  |  |  |                         load_dh_params = None | 
					
						
							|  |  |  |                         raise RuntimeError | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         raise | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     actual_mode = [(a[0], a[1]) for e, a in hook.seen if e == "open" and a[1]] | 
					
						
							|  |  |  |     actual_flag = [(a[0], a[2]) for e, a in hook.seen if e == "open" and not a[1]] | 
					
						
							|  |  |  |     assertSequenceEqual( | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             i | 
					
						
							|  |  |  |             for i in [ | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |                 (testfn, "r"), | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  |                 (sys.executable, "r"), | 
					
						
							|  |  |  |                 (3, "w"), | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |                 (testfn, "w"), | 
					
						
							|  |  |  |                 (testfn, "rb") if load_dh_params else None, | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  |             ] | 
					
						
							|  |  |  |             if i is not None | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |         actual_mode, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     assertSequenceEqual([], actual_flag) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_cantrace(): | 
					
						
							|  |  |  |     traced = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def trace(frame, event, *args): | 
					
						
							|  |  |  |         if frame.f_code == TestHook.__call__.__code__: | 
					
						
							|  |  |  |             traced.append(event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     old = sys.settrace(trace) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         with TestHook() as hook: | 
					
						
							|  |  |  |             # No traced call | 
					
						
							|  |  |  |             eval("1") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # No traced call | 
					
						
							|  |  |  |             hook.__cantrace__ = False | 
					
						
							|  |  |  |             eval("2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # One traced call | 
					
						
							|  |  |  |             hook.__cantrace__ = True | 
					
						
							|  |  |  |             eval("3") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Two traced calls (writing to private member, eval) | 
					
						
							|  |  |  |             hook.__cantrace__ = 1 | 
					
						
							|  |  |  |             eval("4") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # One traced call (writing to private member) | 
					
						
							|  |  |  |             hook.__cantrace__ = 0 | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         sys.settrace(old) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     assertSequenceEqual(["call"] * 4, traced) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 09:31:59 -06:00
										 |  |  | def test_mmap(): | 
					
						
							|  |  |  |     import mmap | 
					
						
							| 
									
										
										
										
											2019-11-28 08:46:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 09:31:59 -06:00
										 |  |  |     with TestHook() as hook: | 
					
						
							|  |  |  |         mmap.mmap(-1, 8) | 
					
						
							|  |  |  |         assertEqual(hook.seen[0][1][:2], (-1, 8)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-28 08:46:11 -08:00
										 |  |  | def test_excepthook(): | 
					
						
							|  |  |  |     def excepthook(exc_type, exc_value, exc_tb): | 
					
						
							|  |  |  |         if exc_type is not RuntimeError: | 
					
						
							|  |  |  |             sys.__excepthook__(exc_type, exc_value, exc_tb) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event == "sys.excepthook": | 
					
						
							|  |  |  |             if not isinstance(args[2], args[1]): | 
					
						
							|  |  |  |                 raise TypeError(f"Expected isinstance({args[2]!r}, " f"{args[1]!r})") | 
					
						
							|  |  |  |             if args[0] != excepthook: | 
					
						
							|  |  |  |                 raise ValueError(f"Expected {args[0]} == {excepthook}") | 
					
						
							|  |  |  |             print(event, repr(args[2])) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     sys.excepthook = excepthook | 
					
						
							|  |  |  |     raise RuntimeError("fatal-error") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def test_unraisablehook(): | 
					
						
							| 
									
										
										
										
											2023-11-03 09:45:53 +02:00
										 |  |  |     from _testcapi import err_formatunraisable | 
					
						
							| 
									
										
										
										
											2019-11-28 08:46:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def unraisablehook(hookargs): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event == "sys.unraisablehook": | 
					
						
							|  |  |  |             if args[0] != unraisablehook: | 
					
						
							|  |  |  |                 raise ValueError(f"Expected {args[0]} == {unraisablehook}") | 
					
						
							|  |  |  |             print(event, repr(args[1].exc_value), args[1].err_msg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     sys.unraisablehook = unraisablehook | 
					
						
							| 
									
										
										
										
											2023-11-03 09:45:53 +02:00
										 |  |  |     err_formatunraisable(RuntimeError("nonfatal-error"), | 
					
						
							|  |  |  |                          "Exception ignored for audit hook test") | 
					
						
							| 
									
										
										
										
											2019-11-28 08:46:11 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 11:18:12 -08:00
										 |  |  | def test_winreg(): | 
					
						
							|  |  |  |     from winreg import OpenKey, EnumKey, CloseKey, HKEY_LOCAL_MACHINE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if not event.startswith("winreg."): | 
					
						
							|  |  |  |             return | 
					
						
							|  |  |  |         print(event, *args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     k = OpenKey(HKEY_LOCAL_MACHINE, "Software") | 
					
						
							|  |  |  |     EnumKey(k, 0) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         EnumKey(k, 10000) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         raise RuntimeError("Expected EnumKey(HKLM, 10000) to fail") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     kv = k.Detach() | 
					
						
							|  |  |  |     CloseKey(kv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 12:38:53 +01:00
										 |  |  | def test_socket(): | 
					
						
							|  |  |  |     import socket | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("socket."): | 
					
						
							|  |  |  |             print(event, *args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     socket.gethostname() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Don't care if this fails, we just want the audit message | 
					
						
							|  |  |  |     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         # Don't care if this fails, we just want the audit message | 
					
						
							|  |  |  |         sock.bind(('127.0.0.1', 8080)) | 
					
						
							| 
									
										
										
										
											2020-04-01 09:38:26 +01:00
										 |  |  |     except Exception: | 
					
						
							| 
									
										
										
										
											2020-03-31 12:38:53 +01:00
										 |  |  |         pass | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         sock.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 00:53:57 +00:00
										 |  |  | 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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-23 03:19:08 -07:00
										 |  |  | def test_http_client(): | 
					
						
							|  |  |  |     import http.client | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("http.client."): | 
					
						
							|  |  |  |             print(event, *args[1:]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     conn = http.client.HTTPConnection('www.python.org') | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         conn.request('GET', '/') | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         print('http.client.send', '[cannot send]') | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         conn.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-27 01:16:46 +02:00
										 |  |  | def test_sqlite3(): | 
					
						
							|  |  |  |     import sqlite3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, *args): | 
					
						
							|  |  |  |         if event.startswith("sqlite3."): | 
					
						
							|  |  |  |             print(event, *args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							| 
									
										
										
										
											2021-05-02 23:25:17 +02:00
										 |  |  |     cx1 = sqlite3.connect(":memory:") | 
					
						
							|  |  |  |     cx2 = sqlite3.Connection(":memory:") | 
					
						
							| 
									
										
										
										
											2021-04-27 01:16:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Configured without --enable-loadable-sqlite-extensions | 
					
						
							| 
									
										
										
										
											2023-08-23 12:10:08 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         if hasattr(sqlite3.Connection, "enable_load_extension"): | 
					
						
							|  |  |  |             cx1.enable_load_extension(False) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 cx1.load_extension("test") | 
					
						
							|  |  |  |             except sqlite3.OperationalError: | 
					
						
							|  |  |  |                 pass | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise RuntimeError("Expected sqlite3.load_extension to fail") | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         cx1.close() | 
					
						
							|  |  |  |         cx2.close() | 
					
						
							| 
									
										
										
										
											2021-04-27 01:16:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-17 16:11:24 +01:00
										 |  |  | def test_sys_getframe(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("sys."): | 
					
						
							|  |  |  |             print(event, args[0].f_code.co_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     sys._getframe() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-13 11:31:06 +00:00
										 |  |  | def test_sys_getframemodulename(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("sys."): | 
					
						
							|  |  |  |             print(event, *args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     sys._getframemodulename() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-16 17:15:52 +00:00
										 |  |  | def test_threading(): | 
					
						
							|  |  |  |     import _thread | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith(("_thread.", "cpython.PyThreadState", "test.")): | 
					
						
							|  |  |  |             print(event, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lock = _thread.allocate_lock() | 
					
						
							|  |  |  |     lock.acquire() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class test_func: | 
					
						
							|  |  |  |         def __repr__(self): return "<test_func>" | 
					
						
							|  |  |  |         def __call__(self): | 
					
						
							|  |  |  |             sys.audit("test.test_func") | 
					
						
							|  |  |  |             lock.release() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = _thread.start_new_thread(test_func(), ()) | 
					
						
							|  |  |  |     lock.acquire() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-04 14:59:24 +01:00
										 |  |  |     handle = _thread.start_joinable_thread(test_func()) | 
					
						
							|  |  |  |     handle.join() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-16 17:15:52 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def test_threading_abort(): | 
					
						
							|  |  |  |     # Ensures that aborting PyThreadState_New raises the correct exception | 
					
						
							|  |  |  |     import _thread | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class ThreadNewAbortError(Exception): | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event == "cpython.PyThreadState_New": | 
					
						
							|  |  |  |             raise ThreadNewAbortError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         _thread.start_new_thread(lambda: None, ()) | 
					
						
							|  |  |  |     except ThreadNewAbortError: | 
					
						
							|  |  |  |         # Other exceptions are raised and the test will fail | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | def test_wmi_exec_query(): | 
					
						
							|  |  |  |     import _wmi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("_wmi."): | 
					
						
							|  |  |  |             print(event, args[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							| 
									
										
										
										
											2024-01-26 14:38:24 +00:00
										 |  |  |     try: | 
					
						
							|  |  |  |         _wmi.exec_query("SELECT * FROM Win32_OperatingSystem") | 
					
						
							|  |  |  |     except WindowsError as e: | 
					
						
							|  |  |  |         # gh-112278: WMI may be slow response when first called, but we still | 
					
						
							|  |  |  |         # get the audit event, so just ignore the timeout | 
					
						
							|  |  |  |         if e.winerror != 258: | 
					
						
							|  |  |  |             raise | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-07 20:17:08 +03:00
										 |  |  | def test_syslog(): | 
					
						
							|  |  |  |     import syslog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("syslog."): | 
					
						
							|  |  |  |             print(event, *args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     syslog.openlog('python') | 
					
						
							|  |  |  |     syslog.syslog('test') | 
					
						
							|  |  |  |     syslog.setlogmask(syslog.LOG_DEBUG) | 
					
						
							|  |  |  |     syslog.closelog() | 
					
						
							|  |  |  |     # implicit open | 
					
						
							|  |  |  |     syslog.syslog('test2') | 
					
						
							|  |  |  |     # open with default ident | 
					
						
							|  |  |  |     syslog.openlog(logoption=syslog.LOG_NDELAY, facility=syslog.LOG_LOCAL0) | 
					
						
							|  |  |  |     sys.argv = None | 
					
						
							|  |  |  |     syslog.openlog() | 
					
						
							|  |  |  |     syslog.closelog() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-07 21:09:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 21:39:18 +00:00
										 |  |  | def test_not_in_gc(): | 
					
						
							|  |  |  |     import gc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hook = lambda *a: None | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for o in gc.get_objects(): | 
					
						
							|  |  |  |         if isinstance(o, list): | 
					
						
							|  |  |  |             assert hook not in o | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  | def test_time(mode): | 
					
						
							| 
									
										
										
										
											2023-08-23 11:00:22 +02:00
										 |  |  |     import time | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("time."): | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |             if mode == 'print': | 
					
						
							|  |  |  |                 print(event, *args) | 
					
						
							|  |  |  |             elif mode == 'fail': | 
					
						
							|  |  |  |                 raise AssertionError('hook failed') | 
					
						
							| 
									
										
										
										
											2023-08-23 11:00:22 +02:00
										 |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     time.sleep(0) | 
					
						
							|  |  |  |     time.sleep(0.0625)  # 1/16, a small exact float | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         time.sleep(-1) | 
					
						
							|  |  |  |     except ValueError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 12:29:06 +01:00
										 |  |  | def test_sys_monitoring_register_callback(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event.startswith("sys.monitoring"): | 
					
						
							|  |  |  |             print(event, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     sys.monitoring.register_callback(1, 1, None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-31 18:22:30 +02:00
										 |  |  | def test_winapi_createnamedpipe(pipe_name): | 
					
						
							|  |  |  |     import _winapi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def hook(event, args): | 
					
						
							|  |  |  |         if event == "_winapi.CreateNamedPipe": | 
					
						
							|  |  |  |             print(event, args) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sys.addaudithook(hook) | 
					
						
							|  |  |  |     _winapi.CreateNamedPipe(pipe_name, _winapi.PIPE_ACCESS_DUPLEX, 8, 2, 0, 0, 0, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-27 16:07:33 +01:00
										 |  |  | def test_assert_unicode(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  |     sys.addaudithook(lambda *args: None) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         sys.audit(9) | 
					
						
							|  |  |  |     except TypeError: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         raise RuntimeError("Expected sys.audit(9) to fail.") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | if __name__ == "__main__": | 
					
						
							| 
									
										
										
										
											2020-06-10 18:49:23 +02:00
										 |  |  |     from test.support import suppress_msvcrt_asserts | 
					
						
							| 
									
										
										
										
											2019-11-28 08:46:11 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-10 18:49:23 +02:00
										 |  |  |     suppress_msvcrt_asserts() | 
					
						
							| 
									
										
										
										
											2019-05-29 08:20:35 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     test = sys.argv[1] | 
					
						
							| 
									
										
										
										
											2023-09-05 10:25:08 +02:00
										 |  |  |     globals()[test](*sys.argv[2:]) |