From 8ed317f1ca42a43df14282bbc3ccc0b5610432f4 Mon Sep 17 00:00:00 2001 From: costypetrisor Date: Tue, 31 Jul 2018 20:55:14 +0000 Subject: [PATCH] bpo-34113: Fix a crash when using LLTRACE is on (GH-8517) Fix a crash on negative STACKADJ() when Low-Level trace (LLTRACE) is enabled. --- Lib/test/test_lltrace.py | 31 +++++++++++++ .../2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst | 2 + Python/ceval.c | 44 ++++++++++++------- 3 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 Lib/test/test_lltrace.py create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst diff --git a/Lib/test/test_lltrace.py b/Lib/test/test_lltrace.py new file mode 100644 index 00000000000..49fae81eefa --- /dev/null +++ b/Lib/test/test_lltrace.py @@ -0,0 +1,31 @@ +import os +import textwrap +import unittest + +from test import support +from test.support.script_helper import assert_python_ok + + +class TestLLTrace(unittest.TestCase): + + def test_lltrace_does_not_crash_on_subscript_operator(self): + # If this test fails, it will reproduce a crash reported as + # bpo-34113. The crash happened at the command line console of + # debug Python builds with __ltrace__ enabled (only possible in console), + # when the interal Python stack was negatively adjusted + with open(support.TESTFN, 'w') as fd: + self.addCleanup(os.unlink, support.TESTFN) + fd.write(textwrap.dedent("""\ + import code + + console = code.InteractiveConsole() + console.push('__ltrace__ = 1') + console.push('a = [1, 2, 3]') + console.push('a[0] = 1') + print('unreachable if bug exists') + """)) + + assert_python_ok(support.TESTFN) + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst b/Misc/NEWS.d/next/Core and Builtins/2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst new file mode 100644 index 00000000000..f4c80f9b8a9 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst @@ -0,0 +1,2 @@ +Fixed crash on debug builds when opcode stack was adjusted with negative +numbers. Patch by Constantin Petrisor. diff --git a/Python/ceval.c b/Python/ceval.c index 8f0e0e00c2b..46da295aac0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -762,16 +762,26 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag) assert(STACK_LEVEL() <= co->co_stacksize); } #define POP() ((void)(lltrace && prtrace(TOP(), "pop")), \ BASIC_POP()) -#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \ +#define STACK_GROW(n) do { \ + assert(n >= 0); \ + (void)(BASIC_STACKADJ(n), \ lltrace && prtrace(TOP(), "stackadj")); \ - assert(STACK_LEVEL() <= co->co_stacksize); } + assert(STACK_LEVEL() <= co->co_stacksize); \ + } while (0) +#define STACK_SHRINK(n) do { \ + assert(n >= 0); \ + (void)(lltrace && prtrace(TOP(), "stackadj")); \ + (void)(BASIC_STACKADJ(-n)); \ + assert(STACK_LEVEL() <= co->co_stacksize); \ + } while (0) #define EXT_POP(STACK_POINTER) ((void)(lltrace && \ prtrace((STACK_POINTER)[-1], "ext_pop")), \ *--(STACK_POINTER)) #else #define PUSH(v) BASIC_PUSH(v) #define POP() BASIC_POP() -#define STACKADJ(n) BASIC_STACKADJ(n) +#define STACK_GROW(n) BASIC_STACKADJ(n) +#define STACK_SHRINK(n) BASIC_STACKADJ(-n) #define EXT_POP(STACK_POINTER) (*--(STACK_POINTER)) #endif @@ -1133,7 +1143,7 @@ main_loop: PyObject *second = SECOND(); Py_INCREF(top); Py_INCREF(second); - STACKADJ(2); + STACK_GROW(2); SET_TOP(top); SET_SECOND(second); FAST_DISPATCH(); @@ -1173,7 +1183,7 @@ main_loop: SET_TOP(Py_False); DISPATCH(); } - STACKADJ(-1); + STACK_SHRINK(1); goto error; } @@ -1569,7 +1579,7 @@ main_loop: PyObject *container = SECOND(); PyObject *v = THIRD(); int err; - STACKADJ(-3); + STACK_SHRINK(3); /* container[sub] = v */ err = PyObject_SetItem(container, sub, v); Py_DECREF(v); @@ -1584,7 +1594,7 @@ main_loop: PyObject *sub = TOP(); PyObject *container = SECOND(); int err; - STACKADJ(-2); + STACK_SHRINK(2); /* del container[sub] */ err = PyObject_DelItem(container, sub); Py_DECREF(container); @@ -2067,7 +2077,7 @@ main_loop: } } else if (unpack_iterable(seq, oparg, -1, stack_pointer + oparg)) { - STACKADJ(oparg); + STACK_GROW(oparg); } else { /* unpack_iterable() raised an exception */ Py_DECREF(seq); @@ -2097,7 +2107,7 @@ main_loop: PyObject *owner = TOP(); PyObject *v = SECOND(); int err; - STACKADJ(-2); + STACK_SHRINK(2); err = PyObject_SetAttr(owner, name, v); Py_DECREF(v); Py_DECREF(owner); @@ -2420,7 +2430,7 @@ main_loop: err = PySet_Add(set, item); Py_DECREF(item); } - STACKADJ(-oparg); + STACK_SHRINK(oparg); if (err != 0) { Py_DECREF(set); goto error; @@ -2641,7 +2651,7 @@ main_loop: PyObject *value = SECOND(); PyObject *map; int err; - STACKADJ(-2); + STACK_SHRINK(2); map = PEEK(oparg); /* dict */ assert(PyDict_CheckExact(map)); err = PyDict_SetItem(map, key, value); /* map[key] = value */ @@ -2784,7 +2794,7 @@ main_loop: PyObject *cond = TOP(); int err; if (cond == Py_True) { - STACKADJ(-1); + STACK_SHRINK(1); Py_DECREF(cond); FAST_DISPATCH(); } @@ -2794,7 +2804,7 @@ main_loop: } err = PyObject_IsTrue(cond); if (err > 0) { - STACKADJ(-1); + STACK_SHRINK(1); Py_DECREF(cond); } else if (err == 0) @@ -2808,7 +2818,7 @@ main_loop: PyObject *cond = TOP(); int err; if (cond == Py_False) { - STACKADJ(-1); + STACK_SHRINK(1); Py_DECREF(cond); FAST_DISPATCH(); } @@ -2821,7 +2831,7 @@ main_loop: JUMPTO(oparg); } else if (err == 0) { - STACKADJ(-1); + STACK_SHRINK(1); Py_DECREF(cond); } else @@ -2907,7 +2917,7 @@ main_loop: PyErr_Clear(); } /* iterator ended normally */ - STACKADJ(-1); + STACK_SHRINK(1); Py_DECREF(iter); JUMPBY(oparg); PREDICT(POP_BLOCK); @@ -3015,7 +3025,7 @@ main_loop: val = tb = Py_None; exc = TOP(); if (exc == NULL) { - STACKADJ(-1); + STACK_SHRINK(1); exit_func = TOP(); SET_TOP(exc); exc = Py_None;