Commit 60934627 authored by Michael W. Hudson's avatar Michael W. Hudson

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.
parent fd39ad49
from test.test_support import verbose, verify from test.test_support import verbose, verify, TestFailed
import sys import sys
import new import new
...@@ -99,11 +99,67 @@ print 'new.code()' ...@@ -99,11 +99,67 @@ print 'new.code()'
# bogus test of new.code() # bogus test of new.code()
# Note: Jython will never have new.code() # Note: Jython will never have new.code()
if hasattr(new, 'code'): if hasattr(new, 'code'):
# XXX should use less criminally bogus arguments! def f(a): pass
d = new.code(3, 3, 3, 3, codestr, (), (), (),
"<string>", "<name>", 1, "", (), ()) 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 # test backwards-compatibility version with no freevars or cellvars
d = new.code(3, 3, 3, 3, codestr, (), (), (), d = new.code(argcount, nlocals, stacksize, flags, codestring,
"<string>", "<name>", 1, "") 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: if verbose:
print d print d
...@@ -88,6 +88,50 @@ static PyMemberDef code_memberlist[] = { ...@@ -88,6 +88,50 @@ static PyMemberDef code_memberlist[] = {
{NULL} /* Sentinel */ {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, PyDoc_STRVAR(code_doc,
"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\ "code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\
varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\ varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\
...@@ -101,14 +145,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -101,14 +145,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
int nlocals; int nlocals;
int stacksize; int stacksize;
int flags; int flags;
PyObject *co; PyObject *co = NULL;;
PyObject *empty = NULL;
PyObject *code; PyObject *code;
PyObject *consts; PyObject *consts;
PyObject *names; PyObject *names, *ournames = NULL;
PyObject *varnames; PyObject *varnames, *ourvarnames = NULL;
PyObject *freevars = NULL; PyObject *freevars = NULL, *ourfreevars = NULL;
PyObject *cellvars = NULL; PyObject *cellvars = NULL, *ourcellvars = NULL;
PyObject *filename; PyObject *filename;
PyObject *name; PyObject *name;
int firstlineno; int firstlineno;
...@@ -126,27 +169,48 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -126,27 +169,48 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
&PyTuple_Type, &cellvars)) &PyTuple_Type, &cellvars))
return NULL; return NULL;
if (!PyObject_CheckReadBuffer(code)) { if (argcount < 0) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(
"bytecode object must be a single-segment read-only buffer"); PyExc_ValueError,
return NULL; "code: argcount must not be negative");
goto cleanup;
} }
if (freevars == NULL || cellvars == NULL) { if (nlocals < 0) {
empty = PyTuple_New(0); PyErr_SetString(
if (empty == NULL) PyExc_ValueError,
return NULL; "code: nlocals must not be negative");
if (freevars == NULL) goto cleanup;
freevars = empty;
if (cellvars == NULL)
cellvars = empty;
} }
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, co = (PyObject *) PyCode_New(argcount, nlocals, stacksize, flags,
code, consts, names, varnames, code, consts, ournames, ourvarnames,
freevars, cellvars, filename, name, ourfreevars, ourcellvars, filename,
firstlineno, lnotab); name, firstlineno, lnotab);
Py_XDECREF(empty); cleanup:
Py_XDECREF(ournames);
Py_XDECREF(ourvarnames);
Py_XDECREF(ourfreevars);
Py_XDECREF(ourcellvars);
return co; return co;
} }
...@@ -302,21 +366,18 @@ all_name_chars(unsigned char *s) ...@@ -302,21 +366,18 @@ all_name_chars(unsigned char *s)
return 1; return 1;
} }
static int static void
intern_strings(PyObject *tuple) intern_strings(PyObject *tuple)
{ {
int i; int i;
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
PyObject *v = PyTuple_GET_ITEM(tuple, i); 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"); Py_FatalError("non-string found in code slot");
PyErr_BadInternalCall();
return -1;
} }
PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i)); PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
} }
return 0;
} }
#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1])) #define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment