Skip to content

Commit ac3c439

Browse files
ZeroIntensitysobolevnvstinnermarkshannon
authored
pythongh-131998: Fix NULL dereference when using an unbound method descriptor in a specialized code path (python#132000)
Co-authored-by: sobolevn <[email protected]> Co-authored-by: Victor Stinner <[email protected]> Co-authored-by: Mark Shannon <[email protected]>
1 parent 3eda146 commit ac3c439

File tree

5 files changed

+47
-0
lines changed

5 files changed

+47
-0
lines changed

Lib/test/test_types.py

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
run_with_locale, cpython_only, no_rerun,
55
MISSING_C_DOCSTRINGS, EqualToForwardRef,
66
)
7+
from test.support.script_helper import assert_python_ok
78
from test.support.import_helper import import_fresh_module
89

910
import collections.abc
@@ -672,6 +673,24 @@ def test_traceback_and_frame_types(self):
672673
def test_capsule_type(self):
673674
self.assertIsInstance(_datetime.datetime_CAPI, types.CapsuleType)
674675

676+
def test_call_unbound_crash(self):
677+
# GH-131998: The specialized instruction would get tricked into dereferencing
678+
# a bound "self" that didn't exist if subsequently called unbound.
679+
code = """if True:
680+
681+
def call(part):
682+
[] + ([] + [])
683+
part.pop()
684+
685+
for _ in range(3):
686+
call(['a'])
687+
try:
688+
call(list)
689+
except TypeError:
690+
pass
691+
"""
692+
assert_python_ok("-c", code)
693+
675694

676695
class UnionTests(unittest.TestCase):
677696

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

+4
Original file line numberDiff line numberDiff line change
@@ -4300,12 +4300,14 @@ dummy_func(
43004300
arguments--;
43014301
total_args++;
43024302
}
4303+
EXIT_IF(total_args == 0);
43034304
PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o;
43044305
EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type));
43054306
PyMethodDef *meth = method->d_method;
43064307
EXIT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS));
43074308
PyTypeObject *d_type = method->d_common.d_type;
43084309
PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]);
4310+
assert(self != NULL);
43094311
EXIT_IF(!Py_IS_TYPE(self, d_type));
43104312
STAT_INC(CALL, hit);
43114313
int nargs = total_args - 1;
@@ -4378,12 +4380,14 @@ dummy_func(
43784380
arguments--;
43794381
total_args++;
43804382
}
4383+
EXIT_IF(total_args == 0);
43814384
PyMethodDescrObject *method = (PyMethodDescrObject *)callable_o;
43824385
/* Builtin METH_FASTCALL methods, without keywords */
43834386
EXIT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type));
43844387
PyMethodDef *meth = method->d_method;
43854388
EXIT_IF(meth->ml_flags != METH_FASTCALL);
43864389
PyObject *self = PyStackRef_AsPyObjectBorrow(arguments[0]);
4390+
assert(self != NULL);
43874391
EXIT_IF(!Py_IS_TYPE(self, method->d_common.d_type));
43884392
STAT_INC(CALL, hit);
43894393
int nargs = total_args - 1;

Python/executor_cases.c.h

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)