summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorTian Gao <gaogaotiantian@hotmail.com>2024-07-18 19:47:22 (GMT)
committerGitHub <noreply@github.com>2024-07-18 19:47:22 (GMT)
commit1ab17782832bb1b6baa915627aead3e3516a0894 (patch)
tree920f54b5c39d3ef65992dce91e4a57c4f7354581 /Lib
parent7431c3799efbd06ed03ee70b64420f45e83b3667 (diff)
downloadcpython-1ab17782832bb1b6baa915627aead3e3516a0894.zip
cpython-1ab17782832bb1b6baa915627aead3e3516a0894.tar.gz
cpython-1ab17782832bb1b6baa915627aead3e3516a0894.tar.bz2
gh-120289: Disallow disable() and clear() in external timer to prevent use-after-free (#120297)
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_cprofile.py37
1 files changed, 37 insertions, 0 deletions
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index 27e8a76..b2595ec 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -30,6 +30,43 @@ class CProfileTest(ProfileTest):
self.assertEqual(cm.unraisable.exc_type, TypeError)
+ def test_evil_external_timer(self):
+ # gh-120289
+ # Disabling profiler in external timer should not crash
+ import _lsprof
+ class EvilTimer():
+ def __init__(self, disable_count):
+ self.count = 0
+ self.disable_count = disable_count
+
+ def __call__(self):
+ self.count += 1
+ if self.count == self.disable_count:
+ profiler_with_evil_timer.disable()
+ return self.count
+
+ # this will trigger external timer to disable profiler at
+ # call event - in initContext in _lsprof.c
+ with support.catch_unraisable_exception() as cm:
+ profiler_with_evil_timer = _lsprof.Profiler(EvilTimer(1))
+ profiler_with_evil_timer.enable()
+ # Make a call to trigger timer
+ (lambda: None)()
+ profiler_with_evil_timer.disable()
+ profiler_with_evil_timer.clear()
+ self.assertEqual(cm.unraisable.exc_type, RuntimeError)
+
+ # this will trigger external timer to disable profiler at
+ # return event - in Stop in _lsprof.c
+ with support.catch_unraisable_exception() as cm:
+ profiler_with_evil_timer = _lsprof.Profiler(EvilTimer(2))
+ profiler_with_evil_timer.enable()
+ # Make a call to trigger timer
+ (lambda: None)()
+ profiler_with_evil_timer.disable()
+ profiler_with_evil_timer.clear()
+ self.assertEqual(cm.unraisable.exc_type, RuntimeError)
+
def test_profile_enable_disable(self):
prof = self.profilerclass()
# Make sure we clean ourselves up if the test fails for some reason.