[Python-checkins] bpo-34113: Fix a crash when using LLTRACE is on (GH-8517)

Victor Stinner webhook-mailer at python.org
Tue Jul 31 16:55:18 EDT 2018


https://github.com/python/cpython/commit/8ed317f1ca42a43df14282bbc3ccc0b5610432f4
commit: 8ed317f1ca42a43df14282bbc3ccc0b5610432f4
branch: master
author: costypetrisor <costypetrisor at users.noreply.github.com>
committer: Victor Stinner <vstinner at redhat.com>
date: 2018-07-31T22:55:14+02:00
summary:

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.

files:
A Lib/test/test_lltrace.py
A Misc/NEWS.d/next/Core and Builtins/2018-07-28-10-34-00.bpo-34113.eZ5FWV.rst
M Python/ceval.c

diff --git a/Lib/test/test_lltrace.py b/Lib/test/test_lltrace.py
new file mode 100644
index 000000000000..49fae81eefab
--- /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 000000000000..f4c80f9b8a97
--- /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 8f0e0e00c2b9..46da295aac06 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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 SET_TOP(Py_False);
                 DISPATCH();
             }
-            STACKADJ(-1);
+            STACK_SHRINK(1);
             goto error;
         }
 
@@ -1569,7 +1579,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 }
             } 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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                     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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             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 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             PyObject *cond = TOP();
             int err;
             if (cond == Py_True) {
-                STACKADJ(-1);
+                STACK_SHRINK(1);
                 Py_DECREF(cond);
                 FAST_DISPATCH();
             }
@@ -2794,7 +2804,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             }
             err = PyObject_IsTrue(cond);
             if (err > 0) {
-                STACKADJ(-1);
+                STACK_SHRINK(1);
                 Py_DECREF(cond);
             }
             else if (err == 0)
@@ -2808,7 +2818,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             PyObject *cond = TOP();
             int err;
             if (cond == Py_False) {
-                STACKADJ(-1);
+                STACK_SHRINK(1);
                 Py_DECREF(cond);
                 FAST_DISPATCH();
             }
@@ -2821,7 +2831,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 JUMPTO(oparg);
             }
             else if (err == 0) {
-                STACKADJ(-1);
+                STACK_SHRINK(1);
                 Py_DECREF(cond);
             }
             else
@@ -2907,7 +2917,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
                 PyErr_Clear();
             }
             /* iterator ended normally */
-            STACKADJ(-1);
+            STACK_SHRINK(1);
             Py_DECREF(iter);
             JUMPBY(oparg);
             PREDICT(POP_BLOCK);
@@ -3015,7 +3025,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             val = tb = Py_None;
             exc = TOP();
             if (exc == NULL) {
-                STACKADJ(-1);
+                STACK_SHRINK(1);
                 exit_func = TOP();
                 SET_TOP(exc);
                 exc = Py_None;



More information about the Python-checkins mailing list