Skip to content

Commit 5911768

Browse files
ZeroIntensitysobolevnvstinnermarkshannon
authored
[3.13] gh-131998: Fix NULL dereference when using an unbound method descriptor in a specialized code path (GH-132000) (#132262)
(cherry picked from commit ac3c439) Co-authored-by: Peter Bierma <[email protected]> Co-authored-by: sobolevn <[email protected]> Co-authored-by: Victor Stinner <[email protected]> Co-authored-by: Mark Shannon <[email protected]>
1 parent a9bb009 commit 5911768

File tree

5 files changed

+41
-0
lines changed

5 files changed

+41
-0
lines changed

Lib/test/test_types.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
MISSING_C_DOCSTRINGS,
77
)
88
from test.test_import import no_rerun
9+
from test.support.script_helper import assert_python_ok
10+
from test.support.import_helper import import_fresh_module
11+
912
import collections.abc
1013
from collections import namedtuple, UserDict
1114
import copy
@@ -648,6 +651,24 @@ def test_traceback_and_frame_types(self):
648651
def test_capsule_type(self):
649652
self.assertIsInstance(_datetime.datetime_CAPI, types.CapsuleType)
650653

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

652673
class UnionTests(unittest.TestCase):
653674

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
@@ -3686,12 +3686,14 @@ dummy_func(
36863686
args--;
36873687
total_args++;
36883688
}
3689+
DEOPT_IF(total_args == 0);
36893690
PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
36903691
DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type));
36913692
PyMethodDef *meth = method->d_method;
36923693
DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS));
36933694
PyTypeObject *d_type = method->d_common.d_type;
36943695
PyObject *self = args[0];
3696+
assert(self != NULL);
36953697
DEOPT_IF(!Py_IS_TYPE(self, d_type));
36963698
STAT_INC(CALL, hit);
36973699
int nargs = total_args - 1;
@@ -3754,11 +3756,13 @@ dummy_func(
37543756
total_args++;
37553757
}
37563758
PyMethodDescrObject *method = (PyMethodDescrObject *)callable;
3759+
DEOPT_IF(total_args == 0);
37573760
/* Builtin METH_FASTCALL methods, without keywords */
37583761
DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type));
37593762
PyMethodDef *meth = method->d_method;
37603763
DEOPT_IF(meth->ml_flags != METH_FASTCALL);
37613764
PyObject *self = args[0];
3765+
assert(self != NULL);
37623766
DEOPT_IF(!Py_IS_TYPE(self, method->d_common.d_type));
37633767
STAT_INC(CALL, hit);
37643768
PyCFunctionFast cfunc =

Python/executor_cases.c.h

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)