Issue #21552: Fixed possible integer overflow of too long string lengths in

the tkinter module on 64-bit platforms.
This commit is contained in:
Serhiy Storchaka 2014-05-30 14:24:03 +03:00
parent 9f1f4f40e4
commit 79851d755b
3 changed files with 64 additions and 2 deletions

View File

@ -557,10 +557,35 @@ class BigmemTclTest(unittest.TestCase):
@support.cpython_only
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@support.bigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False)
def test_huge_string(self, size):
def test_huge_string_call(self, size):
value = ' ' * size
self.assertRaises(OverflowError, self.interp.call, 'set', '_', value)
@support.cpython_only
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@support.bigmemtest(size=INT_MAX + 1, memuse=9, dry_run=False)
def test_huge_string_builtins(self, size):
value = '1' + ' ' * size
self.assertRaises(OverflowError, self.interp.getint, value)
self.assertRaises(OverflowError, self.interp.getdouble, value)
self.assertRaises(OverflowError, self.interp.getboolean, value)
self.assertRaises(OverflowError, self.interp.eval, value)
self.assertRaises(OverflowError, self.interp.evalfile, value)
self.assertRaises(OverflowError, self.interp.record, value)
self.assertRaises(OverflowError, self.interp.adderrorinfo, value)
self.assertRaises(OverflowError, self.interp.setvar, value, 'x', 'a')
self.assertRaises(OverflowError, self.interp.setvar, 'x', value, 'a')
self.assertRaises(OverflowError, self.interp.unsetvar, value)
self.assertRaises(OverflowError, self.interp.unsetvar, 'x', value)
self.assertRaises(OverflowError, self.interp.adderrorinfo, value)
self.assertRaises(OverflowError, self.interp.exprstring, value)
self.assertRaises(OverflowError, self.interp.exprlong, value)
self.assertRaises(OverflowError, self.interp.exprboolean, value)
self.assertRaises(OverflowError, self.interp.splitlist, value)
self.assertRaises(OverflowError, self.interp.split, value)
self.assertRaises(OverflowError, self.interp.createcommand, value, max)
self.assertRaises(OverflowError, self.interp.deletecommand, value)
def setUpModule():
if support.verbose:

View File

@ -18,6 +18,9 @@ Core and Builtins
Library
-------
- Issue #21552: Fixed possible integer overflow of too long string lengths in
the tkinter module on 64-bit platforms.
- Issue #14315: The zipfile module now ignores extra fields in the central
directory that are too short to be parsed instead of letting a struct.unpack
error bubble up as this "bad data" appears in many real world zip files in

View File

@ -861,6 +861,16 @@ static PyType_Spec PyTclObject_Type_spec = {
};
#if PY_SIZE_MAX > INT_MAX
#define CHECK_STRING_LENGTH(s) do { \
if (s != NULL && strlen(s) >= INT_MAX) { \
PyErr_SetString(PyExc_OverflowError, "string is too long"); \
return NULL; \
} } while(0)
#else
#define CHECK_STRING_LENGTH(s)
#endif
static Tcl_Obj*
AsObj(PyObject *value)
{
@ -1279,6 +1289,7 @@ Tkapp_Eval(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:eval", &script))
return NULL;
CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1302,6 +1313,7 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
return NULL;
CHECK_STRING_LENGTH(fileName);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1322,9 +1334,10 @@ Tkapp_Record(PyObject *self, PyObject *args)
PyObject *res = NULL;
int err;
if (!PyArg_ParseTuple(args, "s", &script))
if (!PyArg_ParseTuple(args, "s:record", &script))
return NULL;
CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1345,6 +1358,7 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
return NULL;
CHECK_STRING_LENGTH(msg);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1528,6 +1542,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "ssO:setvar",
&name1, &name2, &newValue))
return NULL;
CHECK_STRING_LENGTH(name1);
CHECK_STRING_LENGTH(name2);
/* XXX must hold tcl lock already??? */
newval = AsObj(newValue);
ENTER_TCL
@ -1573,6 +1589,7 @@ GetVar(PyObject *self, PyObject *args, int flags)
varname_converter, &name1, &name2))
return NULL;
CHECK_STRING_LENGTH(name2);
ENTER_TCL
tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
@ -1615,6 +1632,8 @@ UnsetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
return NULL;
CHECK_STRING_LENGTH(name1);
CHECK_STRING_LENGTH(name2);
ENTER_TCL
code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP
@ -1660,6 +1679,7 @@ Tkapp_GetInt(PyObject *self, PyObject *args)
}
if (!PyArg_ParseTuple(args, "s:getint", &s))
return NULL;
CHECK_STRING_LENGTH(s);
if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error(self);
return Py_BuildValue("i", v);
@ -1680,6 +1700,7 @@ Tkapp_GetDouble(PyObject *self, PyObject *args)
}
if (!PyArg_ParseTuple(args, "s:getdouble", &s))
return NULL;
CHECK_STRING_LENGTH(s);
if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error(self);
return Py_BuildValue("d", v);
@ -1700,6 +1721,7 @@ Tkapp_GetBoolean(PyObject *self, PyObject *args)
}
if (!PyArg_ParseTuple(args, "s:getboolean", &s))
return NULL;
CHECK_STRING_LENGTH(s);
if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR)
return Tkinter_Error(self);
return PyBool_FromLong(v);
@ -1715,6 +1737,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprstring", &s))
return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1739,6 +1762,7 @@ Tkapp_ExprLong(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprlong", &s))
return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
@ -1762,6 +1786,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
ENTER_TCL
@ -1786,6 +1811,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT;
ENTER_TCL
retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
@ -1838,6 +1864,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
return NULL;
CHECK_STRING_LENGTH(list);
if (Tcl_SplitList(Tkapp_Interp(self), list,
&argc, &argv) == TCL_ERROR) {
PyMem_Free(list);
@ -1899,6 +1926,7 @@ Tkapp_Split(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
return NULL;
CHECK_STRING_LENGTH(list);
v = Split(list);
PyMem_Free(list);
return v;
@ -2030,6 +2058,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
return NULL;
CHECK_STRING_LENGTH(cmdName);
if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "command not callable");
return NULL;
@ -2091,6 +2120,7 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
return NULL;
CHECK_STRING_LENGTH(cmdName);
#ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
@ -2782,6 +2812,10 @@ Tkinter_Create(PyObject *self, PyObject *args)
&interactive, &wantobjects, &wantTk,
&sync, &use))
return NULL;
CHECK_STRING_LENGTH(screenName);
CHECK_STRING_LENGTH(baseName);
CHECK_STRING_LENGTH(className);
CHECK_STRING_LENGTH(use);
return (PyObject *) Tkapp_New(screenName, className,
interactive, wantobjects, wantTk,