Fix bug
[ 1005248 ] new.code() not cleanly checking its arguments using the result of new.code() can still destroy the sun, but merely calling the function shouldn't any more. I also rewrote the existing tests of new.code() to use vastly less un-bogus arguments, and added tests for the previous insane behaviours.
This commit is contained in:
parent
fd39ad4937
commit
6093462739
|
@ -1,4 +1,4 @@
|
|||
from test.test_support import verbose, verify
|
||||
from test.test_support import verbose, verify, TestFailed
|
||||
import sys
|
||||
import new
|
||||
|
||||
|
@ -99,11 +99,67 @@ print 'new.code()'
|
|||
# bogus test of new.code()
|
||||
# Note: Jython will never have new.code()
|
||||
if hasattr(new, 'code'):
|
||||
# XXX should use less criminally bogus arguments!
|
||||
d = new.code(3, 3, 3, 3, codestr, (), (), (),
|
||||
"<string>", "<name>", 1, "", (), ())
|
||||
def f(a): pass
|
||||
|
||||
c = f.func_code
|
||||
argcount = c.co_argcount
|
||||
nlocals = c.co_nlocals
|
||||
stacksize = c.co_stacksize
|
||||
flags = c.co_flags
|
||||
codestring = c.co_code
|
||||
constants = c.co_consts
|
||||
names = c.co_names
|
||||
varnames = c.co_varnames
|
||||
filename = c.co_filename
|
||||
name = c.co_name
|
||||
firstlineno = c.co_firstlineno
|
||||
lnotab = c.co_lnotab
|
||||
freevars = c.co_freevars
|
||||
cellvars = c.co_cellvars
|
||||
|
||||
d = new.code(argcount, nlocals, stacksize, flags, codestring,
|
||||
constants, names, varnames, filename, name,
|
||||
firstlineno, lnotab, freevars, cellvars)
|
||||
|
||||
# test backwards-compatibility version with no freevars or cellvars
|
||||
d = new.code(3, 3, 3, 3, codestr, (), (), (),
|
||||
"<string>", "<name>", 1, "")
|
||||
d = new.code(argcount, nlocals, stacksize, flags, codestring,
|
||||
constants, names, varnames, filename, name,
|
||||
firstlineno, lnotab)
|
||||
|
||||
try: # this used to trigger a SystemError
|
||||
d = new.code(-argcount, nlocals, stacksize, flags, codestring,
|
||||
constants, names, varnames, filename, name,
|
||||
firstlineno, lnotab)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "negative co_argcount didn't trigger an exception"
|
||||
|
||||
try: # this used to trigger a SystemError
|
||||
d = new.code(argcount, -nlocals, stacksize, flags, codestring,
|
||||
constants, names, varnames, filename, name,
|
||||
firstlineno, lnotab)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "negative co_nlocals didn't trigger an exception"
|
||||
|
||||
try: # this used to trigger a Py_FatalError!
|
||||
d = new.code(argcount, nlocals, stacksize, flags, codestring,
|
||||
constants, (5,), varnames, filename, name,
|
||||
firstlineno, lnotab)
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
raise TestFailed, "non-string co_name didn't trigger an exception"
|
||||
|
||||
# new.code used to be a way to mutate a tuple...
|
||||
class S(str): pass
|
||||
t = (S("ab"),)
|
||||
d = new.code(argcount, nlocals, stacksize, flags, codestring,
|
||||
constants, t, varnames, filename, name,
|
||||
firstlineno, lnotab)
|
||||
verify(type(t[0]) is S, "eek, tuple changed under us!")
|
||||
|
||||
if verbose:
|
||||
print d
|
||||
|
|
115
Python/compile.c
115
Python/compile.c
|
@ -88,6 +88,50 @@ static PyMemberDef code_memberlist[] = {
|
|||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
/* Helper for code_new: return a shallow copy of a tuple that is
|
||||
guaranteed to contain exact strings, by converting string subclasses
|
||||
to exact strings and complaining if a non-string is found. */
|
||||
static PyObject*
|
||||
validate_and_copy_tuple(PyObject *tup)
|
||||
{
|
||||
PyObject *newtuple;
|
||||
PyObject *item;
|
||||
int i, len;
|
||||
|
||||
len = PyTuple_GET_SIZE(tup);
|
||||
newtuple = PyTuple_New(len);
|
||||
if (newtuple == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
item = PyTuple_GET_ITEM(tup, i);
|
||||
if (PyString_CheckExact(item)) {
|
||||
Py_INCREF(item);
|
||||
}
|
||||
else if (!PyString_Check(item)) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"name tuples must contain only "
|
||||
"strings, not '%.500s'",
|
||||
item->ob_type->tp_name);
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
item = PyString_FromStringAndSize(
|
||||
PyString_AS_STRING(item),
|
||||
PyString_GET_SIZE(item));
|
||||
if (item == NULL) {
|
||||
Py_DECREF(newtuple);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyTuple_SET_ITEM(newtuple, i, item);
|
||||
}
|
||||
|
||||
return newtuple;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(code_doc,
|
||||
"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\
|
||||
varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\
|
||||
|
@ -101,14 +145,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
int nlocals;
|
||||
int stacksize;
|
||||
int flags;
|
||||
PyObject *co;
|
||||
PyObject *empty = NULL;
|
||||
PyObject *co = NULL;;
|
||||
PyObject *code;
|
||||
PyObject *consts;
|
||||
PyObject *names;
|
||||
PyObject *varnames;
|
||||
PyObject *freevars = NULL;
|
||||
PyObject *cellvars = NULL;
|
||||
PyObject *names, *ournames = NULL;
|
||||
PyObject *varnames, *ourvarnames = NULL;
|
||||
PyObject *freevars = NULL, *ourfreevars = NULL;
|
||||
PyObject *cellvars = NULL, *ourcellvars = NULL;
|
||||
PyObject *filename;
|
||||
PyObject *name;
|
||||
int firstlineno;
|
||||
|
@ -126,27 +169,48 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
&PyTuple_Type, &cellvars))
|
||||
return NULL;
|
||||
|
||||
if (!PyObject_CheckReadBuffer(code)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"bytecode object must be a single-segment read-only buffer");
|
||||
return NULL;
|
||||
if (argcount < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: argcount must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (freevars == NULL || cellvars == NULL) {
|
||||
empty = PyTuple_New(0);
|
||||
if (empty == NULL)
|
||||
return NULL;
|
||||
if (freevars == NULL)
|
||||
freevars = empty;
|
||||
if (cellvars == NULL)
|
||||
cellvars = empty;
|
||||
if (nlocals < 0) {
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError,
|
||||
"code: nlocals must not be negative");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ournames = validate_and_copy_tuple(names);
|
||||
if (ournames == NULL)
|
||||
goto cleanup;
|
||||
ourvarnames = validate_and_copy_tuple(varnames);
|
||||
if (ourvarnames == NULL)
|
||||
goto cleanup;
|
||||
if (freevars)
|
||||
ourfreevars = validate_and_copy_tuple(freevars);
|
||||
else
|
||||
ourfreevars = PyTuple_New(0);
|
||||
if (ourfreevars == NULL)
|
||||
goto cleanup;
|
||||
if (cellvars)
|
||||
ourcellvars = validate_and_copy_tuple(cellvars);
|
||||
else
|
||||
ourcellvars = PyTuple_New(0);
|
||||
if (ourcellvars == NULL)
|
||||
goto cleanup;
|
||||
|
||||
co = (PyObject *) PyCode_New(argcount, nlocals, stacksize, flags,
|
||||
code, consts, names, varnames,
|
||||
freevars, cellvars, filename, name,
|
||||
firstlineno, lnotab);
|
||||
Py_XDECREF(empty);
|
||||
code, consts, ournames, ourvarnames,
|
||||
ourfreevars, ourcellvars, filename,
|
||||
name, firstlineno, lnotab);
|
||||
cleanup:
|
||||
Py_XDECREF(ournames);
|
||||
Py_XDECREF(ourvarnames);
|
||||
Py_XDECREF(ourfreevars);
|
||||
Py_XDECREF(ourcellvars);
|
||||
return co;
|
||||
}
|
||||
|
||||
|
@ -302,21 +366,18 @@ all_name_chars(unsigned char *s)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
intern_strings(PyObject *tuple)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
||||
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
||||
if (v == NULL || !PyString_Check(v)) {
|
||||
if (v == NULL || !PyString_CheckExact(v)) {
|
||||
Py_FatalError("non-string found in code slot");
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
|
||||
|
|
Loading…
Reference in New Issue