Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6093462

Browse files
author
Michael W. Hudson
committed
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.
1 parent fd39ad4 commit 6093462

2 files changed

Lines changed: 150 additions & 33 deletions

File tree

Lib/test/test_new.py

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test.test_support import verbose, verify
1+
from test.test_support import verbose, verify, TestFailed
22
import sys
33
import new
44

@@ -99,11 +99,67 @@ def test_closure(func, closure, exc):
9999
# bogus test of new.code()
100100
# Note: Jython will never have new.code()
101101
if hasattr(new, 'code'):
102-
# XXX should use less criminally bogus arguments!
103-
d = new.code(3, 3, 3, 3, codestr, (), (), (),
104-
"<string>", "<name>", 1, "", (), ())
102+
def f(a): pass
103+
104+
c = f.func_code
105+
argcount = c.co_argcount
106+
nlocals = c.co_nlocals
107+
stacksize = c.co_stacksize
108+
flags = c.co_flags
109+
codestring = c.co_code
110+
constants = c.co_consts
111+
names = c.co_names
112+
varnames = c.co_varnames
113+
filename = c.co_filename
114+
name = c.co_name
115+
firstlineno = c.co_firstlineno
116+
lnotab = c.co_lnotab
117+
freevars = c.co_freevars
118+
cellvars = c.co_cellvars
119+
120+
d = new.code(argcount, nlocals, stacksize, flags, codestring,
121+
constants, names, varnames, filename, name,
122+
firstlineno, lnotab, freevars, cellvars)
123+
105124
# test backwards-compatibility version with no freevars or cellvars
106-
d = new.code(3, 3, 3, 3, codestr, (), (), (),
107-
"<string>", "<name>", 1, "")
125+
d = new.code(argcount, nlocals, stacksize, flags, codestring,
126+
constants, names, varnames, filename, name,
127+
firstlineno, lnotab)
128+
129+
try: # this used to trigger a SystemError
130+
d = new.code(-argcount, nlocals, stacksize, flags, codestring,
131+
constants, names, varnames, filename, name,
132+
firstlineno, lnotab)
133+
except ValueError:
134+
pass
135+
else:
136+
raise TestFailed, "negative co_argcount didn't trigger an exception"
137+
138+
try: # this used to trigger a SystemError
139+
d = new.code(argcount, -nlocals, stacksize, flags, codestring,
140+
constants, names, varnames, filename, name,
141+
firstlineno, lnotab)
142+
except ValueError:
143+
pass
144+
else:
145+
raise TestFailed, "negative co_nlocals didn't trigger an exception"
146+
147+
try: # this used to trigger a Py_FatalError!
148+
d = new.code(argcount, nlocals, stacksize, flags, codestring,
149+
constants, (5,), varnames, filename, name,
150+
firstlineno, lnotab)
151+
except TypeError:
152+
pass
153+
else:
154+
raise TestFailed, "non-string co_name didn't trigger an exception"
155+
156+
# new.code used to be a way to mutate a tuple...
157+
class S(str): pass
158+
t = (S("ab"),)
159+
d = new.code(argcount, nlocals, stacksize, flags, codestring,
160+
constants, t, varnames, filename, name,
161+
firstlineno, lnotab)
162+
verify(type(t[0]) is S, "eek, tuple changed under us!")
163+
108164
if verbose:
109165
print d

Python/compile.c

Lines changed: 88 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,50 @@ static PyMemberDef code_memberlist[] = {
8888
{NULL} /* Sentinel */
8989
};
9090

91+
/* Helper for code_new: return a shallow copy of a tuple that is
92+
guaranteed to contain exact strings, by converting string subclasses
93+
to exact strings and complaining if a non-string is found. */
94+
static PyObject*
95+
validate_and_copy_tuple(PyObject *tup)
96+
{
97+
PyObject *newtuple;
98+
PyObject *item;
99+
int i, len;
100+
101+
len = PyTuple_GET_SIZE(tup);
102+
newtuple = PyTuple_New(len);
103+
if (newtuple == NULL)
104+
return NULL;
105+
106+
for (i = 0; i < len; i++) {
107+
item = PyTuple_GET_ITEM(tup, i);
108+
if (PyString_CheckExact(item)) {
109+
Py_INCREF(item);
110+
}
111+
else if (!PyString_Check(item)) {
112+
PyErr_Format(
113+
PyExc_TypeError,
114+
"name tuples must contain only "
115+
"strings, not '%.500s'",
116+
item->ob_type->tp_name);
117+
Py_DECREF(newtuple);
118+
return NULL;
119+
}
120+
else {
121+
item = PyString_FromStringAndSize(
122+
PyString_AS_STRING(item),
123+
PyString_GET_SIZE(item));
124+
if (item == NULL) {
125+
Py_DECREF(newtuple);
126+
return NULL;
127+
}
128+
}
129+
PyTuple_SET_ITEM(newtuple, i, item);
130+
}
131+
132+
return newtuple;
133+
}
134+
91135
PyDoc_STRVAR(code_doc,
92136
"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\
93137
varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\
@@ -101,14 +145,13 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
101145
int nlocals;
102146
int stacksize;
103147
int flags;
104-
PyObject *co;
105-
PyObject *empty = NULL;
148+
PyObject *co = NULL;;
106149
PyObject *code;
107150
PyObject *consts;
108-
PyObject *names;
109-
PyObject *varnames;
110-
PyObject *freevars = NULL;
111-
PyObject *cellvars = NULL;
151+
PyObject *names, *ournames = NULL;
152+
PyObject *varnames, *ourvarnames = NULL;
153+
PyObject *freevars = NULL, *ourfreevars = NULL;
154+
PyObject *cellvars = NULL, *ourcellvars = NULL;
112155
PyObject *filename;
113156
PyObject *name;
114157
int firstlineno;
@@ -126,27 +169,48 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
126169
&PyTuple_Type, &cellvars))
127170
return NULL;
128171

129-
if (!PyObject_CheckReadBuffer(code)) {
130-
PyErr_SetString(PyExc_TypeError,
131-
"bytecode object must be a single-segment read-only buffer");
132-
return NULL;
172+
if (argcount < 0) {
173+
PyErr_SetString(
174+
PyExc_ValueError,
175+
"code: argcount must not be negative");
176+
goto cleanup;
133177
}
134178

135-
if (freevars == NULL || cellvars == NULL) {
136-
empty = PyTuple_New(0);
137-
if (empty == NULL)
138-
return NULL;
139-
if (freevars == NULL)
140-
freevars = empty;
141-
if (cellvars == NULL)
142-
cellvars = empty;
179+
if (nlocals < 0) {
180+
PyErr_SetString(
181+
PyExc_ValueError,
182+
"code: nlocals must not be negative");
183+
goto cleanup;
143184
}
144185

186+
ournames = validate_and_copy_tuple(names);
187+
if (ournames == NULL)
188+
goto cleanup;
189+
ourvarnames = validate_and_copy_tuple(varnames);
190+
if (ourvarnames == NULL)
191+
goto cleanup;
192+
if (freevars)
193+
ourfreevars = validate_and_copy_tuple(freevars);
194+
else
195+
ourfreevars = PyTuple_New(0);
196+
if (ourfreevars == NULL)
197+
goto cleanup;
198+
if (cellvars)
199+
ourcellvars = validate_and_copy_tuple(cellvars);
200+
else
201+
ourcellvars = PyTuple_New(0);
202+
if (ourcellvars == NULL)
203+
goto cleanup;
204+
145205
co = (PyObject *) PyCode_New(argcount, nlocals, stacksize, flags,
146-
code, consts, names, varnames,
147-
freevars, cellvars, filename, name,
148-
firstlineno, lnotab);
149-
Py_XDECREF(empty);
206+
code, consts, ournames, ourvarnames,
207+
ourfreevars, ourcellvars, filename,
208+
name, firstlineno, lnotab);
209+
cleanup:
210+
Py_XDECREF(ournames);
211+
Py_XDECREF(ourvarnames);
212+
Py_XDECREF(ourfreevars);
213+
Py_XDECREF(ourcellvars);
150214
return co;
151215
}
152216

@@ -302,21 +366,18 @@ all_name_chars(unsigned char *s)
302366
return 1;
303367
}
304368

305-
static int
369+
static void
306370
intern_strings(PyObject *tuple)
307371
{
308372
int i;
309373

310374
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
311375
PyObject *v = PyTuple_GET_ITEM(tuple, i);
312-
if (v == NULL || !PyString_Check(v)) {
376+
if (v == NULL || !PyString_CheckExact(v)) {
313377
Py_FatalError("non-string found in code slot");
314-
PyErr_BadInternalCall();
315-
return -1;
316378
}
317379
PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i));
318380
}
319-
return 0;
320381
}
321382

322383
#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))

0 commit comments

Comments
 (0)