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.
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 @@
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 @@
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 @@
}
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;