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>
This commit is contained in:
sobolevn 2024-11-02 00:53:29 +03:00 committed by GitHub
parent 72dd4714f9
commit 28b148fb32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 0 deletions

View File

@ -30,6 +30,22 @@ class CProfileTest(ProfileTest):
self.assertEqual(cm.unraisable.exc_type, TypeError) 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): def test_evil_external_timer(self):
# gh-120289 # gh-120289
# Disabling profiler in external timer should not crash # Disabling profiler in external timer should not crash

View File

@ -0,0 +1,2 @@
Fix crash in :class:`!cProfile.Profile` and :class:`!_lsprof.Profiler` when their
callbacks were directly called with 0 arguments.

View File

@ -608,6 +608,12 @@ setBuiltins(ProfilerObject *pObj, int nvalue)
PyObject* pystart_callback(ProfilerObject* self, PyObject *const *args, Py_ssize_t size) 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]; PyObject* code = args[0];
ptrace_enter_call((PyObject*)self, (void *)code, (PyObject *)code); 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) 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]; PyObject* code = args[0];
ptrace_leave_call((PyObject*)self, (void *)code); 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) 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) { if (self->flags & POF_BUILTINS) {
PyObject* callable = args[2]; PyObject* callable = args[2];
PyObject* self_arg = args[3]; 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) 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) { if (self->flags & POF_BUILTINS) {
PyObject* callable = args[2]; PyObject* callable = args[2];
PyObject* self_arg = args[3]; PyObject* self_arg = args[3];