diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/ceval.c | 35 | ||||
-rw-r--r-- | Python/compile.c | 21 | ||||
-rw-r--r-- | Python/peephole.c | 16 |
3 files changed, 35 insertions, 37 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 86dcea2..fe5de03 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2236,6 +2236,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) break; } + case MAKE_CLOSURE: case MAKE_FUNCTION: { int posdefaults = oparg & 0xff; @@ -2245,6 +2246,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) v = POP(); /* code object */ x = PyFunction_New(v, f->f_globals); Py_DECREF(v); + + if (x != NULL && opcode == MAKE_CLOSURE) { + v = POP(); + err = PyFunction_SetClosure(x, v); + Py_DECREF(v); + } if (x != NULL && num_annotations > 0) { Py_ssize_t name_ix; @@ -2308,34 +2315,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) break; } - case MAKE_CLOSURE: - { - v = POP(); /* code object */ - x = PyFunction_New(v, f->f_globals); - Py_DECREF(v); - if (x != NULL) { - v = POP(); - err = PyFunction_SetClosure(x, v); - Py_DECREF(v); - } - if (x != NULL && oparg > 0) { - v = PyTuple_New(oparg); - if (v == NULL) { - Py_DECREF(x); - x = NULL; - break; - } - while (--oparg >= 0) { - w = POP(); - PyTuple_SET_ITEM(v, oparg, w); - } - err = PyFunction_SetDefaults(x, v); - Py_DECREF(v); - } - PUSH(x); - break; - } - case BUILD_SLICE: if (oparg == 3) w = POP(); diff --git a/Python/compile.c b/Python/compile.c index ed0bdcf..7f0fc50 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -836,6 +836,8 @@ opcode_stack_effect(int opcode, int oparg) return -NARGS(oparg)-2; case MAKE_FUNCTION: return -NARGS(oparg) - ((oparg >> 16) & 0xffff); + case MAKE_CLOSURE: + return -1 - NARGS(oparg) - ((oparg >> 16) & 0xffff); #undef NARGS case BUILD_SLICE: if (oparg == 3) @@ -843,8 +845,6 @@ opcode_stack_effect(int opcode, int oparg) else return -1; - case MAKE_CLOSURE: - return -oparg; case LOAD_CLOSURE: return 1; case LOAD_DEREF: @@ -1367,8 +1367,12 @@ static int compiler_visit_annotations(struct compiler *c, arguments_ty args, expr_ty returns) { - /* push arg annotations and a list of the argument names. return the # - of items pushed. this is out-of-order wrt the source code. */ + /* Push arg annotations and a list of the argument names. Return the # + of items pushed. The expressions are evaluated out-of-order wrt the + source code. + + More than 2^16-1 annotations is a SyntaxError. Returns -1 on error. + */ static identifier return_str; PyObject *names; int len; @@ -1399,6 +1403,12 @@ compiler_visit_annotations(struct compiler *c, arguments_ty args, } len = PyList_GET_SIZE(names); + if (len > 65534) { + /* len must fit in 16 bits, and len is incremented below */ + PyErr_SetString(PyExc_SyntaxError, + "too many annotations"); + goto error; + } if (len) { /* convert names to a tuple and place on stack */ PyObject *elt; @@ -1449,6 +1459,9 @@ compiler_function(struct compiler *c, stmt_ty s) if (args->defaults) VISIT_SEQ(c, expr, args->defaults); num_annotations = compiler_visit_annotations(c, args, returns); + if (num_annotations < 0) + return 0; + assert((num_annotations & 0xFFFF) == num_annotations); if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s, s->lineno)) diff --git a/Python/peephole.c b/Python/peephole.c index 28e4c4c..f2e0c0b 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -261,10 +261,12 @@ markblocks(unsigned char *code, int len) The consts object should still be in list form to allow new constants to be appended. - To keep the optimizer simple, it bails out (does nothing) for code - containing extended arguments or that has a length over 32,700. That - allows us to avoid overflow and sign issues. Likewise, it bails when - the lineno table has complex encoding for gaps >= 255. + To keep the optimizer simple, it bails out (does nothing) for code that + has a length over 32,700, and does not calculate extended arguments. + That allows us to avoid overflow and sign issues. Likewise, it bails when + the lineno table has complex encoding for gaps >= 255. EXTENDED_ARG can + appear before MAKE_FUNCTION; in this case both opcodes are skipped. + EXTENDED_ARG preceding any other opcode causes the optimizer to bail. Optimizations are restricted to simple transformations occuring within a single basic block. All transformations keep the code size the same or @@ -535,7 +537,11 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, break; case EXTENDED_ARG: - goto exitUnchanged; + if (codestr[i+3] != MAKE_FUNCTION) + goto exitUnchanged; + /* don't visit MAKE_FUNCTION as GETARG will be wrong */ + i += 3; + break; /* Replace RETURN LOAD_CONST None RETURN with just RETURN */ /* Remove unreachable JUMPs after RETURN */ |