From b2d61bde28d11ab5f31ee7cd2738828f801c68d9 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Mon, 29 Sep 2008 03:41:21 +0000 Subject: The _lsprof module could crash the interpreter if it was given an external timer that did not return a float and a timer was still running when the Profiler object was garbage collected. Fixes issue 3895. Code review by Benjamin Peterson. --- Lib/test/test_cprofile.py | 16 +++++++++++++++- Misc/NEWS | 4 ++++ Modules/_lsprof.c | 11 ++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py index 7ed6cec..13c1060 100755 --- a/Lib/test/test_cprofile.py +++ b/Lib/test/test_cprofile.py @@ -1,7 +1,7 @@ """Test suite for the cProfile module.""" import sys -from test.test_support import run_unittest +from test.test_support import run_unittest, TESTFN, unlink # rip off all interesting stuff from test_profile import cProfile @@ -10,6 +10,20 @@ from test.test_profile import ProfileTest, regenerate_expected_output class CProfileTest(ProfileTest): profilerclass = cProfile.Profile + # Issue 3895. + def test_bad_counter_during_dealloc(self): + import _lsprof + # Must use a file as StringIO doesn't trigger the bug. + sys.stderr = open(TESTFN, 'w') + try: + obj = _lsprof.Profiler(lambda: int) + obj.enable() + obj = _lsprof.Profiler(1) + obj.disable() + finally: + sys.stderr = sys.__stderr__ + unlink(TESTFN) + def test_main(): run_unittest(CProfileTest) diff --git a/Misc/NEWS b/Misc/NEWS index 97fa2b7..466160f 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,10 @@ Core and Builtins Library ------- +- Issue #3895: It was possible to crash the interpreter when an external timer + was used with cProfile that returned an object that could not be converted + into a float. + - Issue #3950: Made turtle respect scale factors. - Issue #3547: Fixed ctypes structures bitfields of varying integer diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 5d18c33..41c477e 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -150,7 +150,16 @@ static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj) } Py_DECREF(o); if (PyErr_Occurred()) { - PyErr_WriteUnraisable((PyObject *) pObj); + PyObject *context = (PyObject *)pObj; + /* May have been called by profiler_dealloc(). */ + if (Py_REFCNT(context) < 1) { + context = PyString_FromString("profiler calling an " + "external timer"); + if (context == NULL) { + return 0; + } + } + PyErr_WriteUnraisable(context); return 0; } return result; -- cgit v0.12