Skip to content

Commit c4aaaf3

Browse files
ZeroIntensitysobolevnvstinnermarkshannon
authored andcommitted
[3.12] gh-131998: Fix NULL dereference when using an unbound method descriptor in a specialized code path (GH-132000)
(cherry picked from commit ac3c439) Co-authored-by: Peter Bierma <zintensitydev@gmail.com> Co-authored-by: sobolevn <mail@sobolevn.me> Co-authored-by: Victor Stinner <vstinner@python.org> Co-authored-by: Mark Shannon <mark@hotpy.org>
1 parent da0b9b9 commit c4aaaf3

4 files changed

Lines changed: 79 additions & 49 deletions

File tree

‎Lib/test/test_types.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
MISSING_C_DOCSTRINGS,
66
)
77
from test.test_import import no_rerun
8+
from test.support.script_helper import assert_python_ok
9+
810
import collections.abc
911
from collections import namedtuple
1012
import copy
@@ -643,6 +645,24 @@ def test_traceback_and_frame_types(self):
643645
self.assertIsInstance(exc.__traceback__, types.TracebackType)
644646
self.assertIsInstance(exc.__traceback__.tb_frame, types.FrameType)
645647

648+
def test_call_unbound_crash(self):
649+
# GH-131998: The specialized instruction would get tricked into dereferencing
650+
# a bound "self" that didn't exist if subsequently called unbound.
651+
code = """if True:
652+
653+
def call(part):
654+
[] + ([] + [])
655+
part.pop()
656+
657+
for _ in range(3):
658+
call(['a'])
659+
try:
660+
call(list)
661+
except TypeError:
662+
pass
663+
"""
664+
assert_python_ok("-c", code)
665+
646666

647667
class UnionTests(unittest.TestCase):
648668

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash when using an unbound method :term:`descriptor` object in a
2+
function where a bound method descriptor was used.

‎Python/bytecodes.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,13 +3108,15 @@ dummy_func(
31083108
args--;
31093109
total_args++;
31103110
}
3111+
DEOPT_IF(total_args == 0, CALL);
31113112
PyMethodDescrObject *callable =
31123113
(PyMethodDescrObject *)PEEK(total_args + 1);
31133114
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
31143115
PyMethodDef *meth = callable->d_method;
31153116
DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL);
31163117
PyTypeObject *d_type = callable->d_common.d_type;
31173118
PyObject *self = args[0];
3119+
assert(self != NULL);
31183120
DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL);
31193121
STAT_INC(CALL, hit);
31203122
int nargs = total_args - 1;
@@ -3173,13 +3175,15 @@ dummy_func(
31733175
args--;
31743176
total_args++;
31753177
}
3178+
DEOPT_IF(total_args == 0, CALL);
31763179
PyMethodDescrObject *callable =
31773180
(PyMethodDescrObject *)PEEK(total_args + 1);
31783181
/* Builtin METH_FASTCALL methods, without keywords */
31793182
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
31803183
PyMethodDef *meth = callable->d_method;
31813184
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
31823185
PyObject *self = args[0];
3186+
assert(self != NULL);
31833187
DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
31843188
STAT_INC(CALL, hit);
31853189
_PyCFunctionFast cfunc =

0 commit comments

Comments
 (0)