summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsobolevn <mail@sobolevn.me>2024-11-01 21:53:29 (GMT)
committerGitHub <noreply@github.com>2024-11-01 21:53:29 (GMT)
commit28b148fb32e4548b461137d18d1ab6d366395d36 (patch)
treea17e95b923a69ed44cdb227b60efe7f9cb109133
parent72dd4714f944e5927656aa25f5cd9bdcd3b00a76 (diff)
downloadcpython-28b148fb32e4548b461137d18d1ab6d366395d36.zip
cpython-28b148fb32e4548b461137d18d1ab6d366395d36.tar.gz
cpython-28b148fb32e4548b461137d18d1ab6d366395d36.tar.bz2
gh-126220: Fix crash on calls to `_lsprof.Profiler` methods with 0 args (backportable) (#126271)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
-rw-r--r--Lib/test/test_cprofile.py16
-rw-r--r--Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst2
-rw-r--r--Modules/_lsprof.c24
3 files changed, 42 insertions, 0 deletions
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index b2595ec..6572087 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -30,6 +30,22 @@ class CProfileTest(ProfileTest):
self.assertEqual(cm.unraisable.exc_type, TypeError)
+ def test_crash_with_not_enough_args(self):
+ # gh-126220
+ import _lsprof
+
+ for profile in [_lsprof.Profiler(), cProfile.Profile()]:
+ for method in [
+ "_pystart_callback",
+ "_pyreturn_callback",
+ "_ccall_callback",
+ "_creturn_callback",
+ ]:
+ with self.subTest(profile=profile, method=method):
+ method_obj = getattr(profile, method)
+ with self.assertRaises(TypeError):
+ method_obj() # should not crash
+
def test_evil_external_timer(self):
# gh-120289
# Disabling profiler in external timer should not crash
diff --git a/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst
new file mode 100644
index 0000000..555f2f3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-31-14-06-28.gh-issue-126220.uJAJCU.rst
@@ -0,0 +1,2 @@
+Fix crash in :class:`!cProfile.Profile` and :class:`!_lsprof.Profiler` when their
+callbacks were directly called with 0 arguments.
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index 8b69062..06958a0 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -608,6 +608,12 @@ setBuiltins(ProfilerObject *pObj, int nvalue)
PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size)
{
+ if (size < 2) {
+ PyErr_Format(PyExc_TypeError,
+ "_pystart_callback expected 2 arguments, got %zd",
+ size);
+ return NULL;
+ }
PyObject* code = args[0];
ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code);
@@ -616,6 +622,12 @@ PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize
PyObject* pyreturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size)
{
+ if (size < 3) {
+ PyErr_Format(PyExc_TypeError,
+ "_pyreturn_callback expected 3 arguments, got %zd",
+ size);
+ return NULL;
+ }
PyObject* code = args[0];
ptrace_leave_call((PyObject*)self, (void *)code);
@@ -651,6 +663,12 @@ PyObject* get_cfunc_from_callable(PyObject* callable, PyObject* self_arg, PyObje
PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size)
{
+ if (size < 4) {
+ PyErr_Format(PyExc_TypeError,
+ "_ccall_callback expected 4 arguments, got %zd",
+ size);
+ return NULL;
+ }
if (self->flags & POF_BUILTINS) {
PyObject* callable = args[2];
PyObject* self_arg = args[3];
@@ -669,6 +687,12 @@ PyObject* ccall_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t
PyObject* creturn_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size)
{
+ if (size < 4) {
+ PyErr_Format(PyExc_TypeError,
+ "_creturn_callback expected 4 arguments, got %zd",
+ size);
+ return NULL;
+ }
if (self->flags & POF_BUILTINS) {
PyObject* callable = args[2];
PyObject* self_arg = args[3];