Commit 2a0220b1 authored by Serhiy Storchaka's avatar Serhiy Storchaka

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

the Tkinter module on 64-bit platforms.
parent d11e8b6a
...@@ -569,6 +569,7 @@ class TclTest(unittest.TestCase): ...@@ -569,6 +569,7 @@ class TclTest(unittest.TestCase):
for arg, res in testcases: for arg, res in testcases:
self.assertEqual(split(arg), res) self.assertEqual(split(arg), res)
character_size = 4 if sys.maxunicode > 0xFFFF else 2
class BigmemTclTest(unittest.TestCase): class BigmemTclTest(unittest.TestCase):
...@@ -578,10 +579,59 @@ class BigmemTclTest(unittest.TestCase): ...@@ -578,10 +579,59 @@ class BigmemTclTest(unittest.TestCase):
@test_support.cpython_only @test_support.cpython_only
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX") @unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@test_support.precisionbigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False) @test_support.precisionbigmemtest(size=INT_MAX + 1, memuse=5, dry_run=False)
def test_huge_string(self, size): def test_huge_string_call(self, size):
value = ' ' * size value = ' ' * size
self.assertRaises(OverflowError, self.interp.call, 'set', '_', value) self.assertRaises(OverflowError, self.interp.call, 'set', '_', value)
@test_support.cpython_only
@unittest.skipUnless(test_support.have_unicode, 'requires unicode support')
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@test_support.precisionbigmemtest(size=INT_MAX + 1,
memuse=2*character_size + 2,
dry_run=False)
def test_huge_unicode_call(self, size):
value = unicode(' ') * size
self.assertRaises(OverflowError, self.interp.call, 'set', '_', value)
@test_support.cpython_only
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@test_support.precisionbigmemtest(size=INT_MAX + 1, memuse=9, dry_run=False)
def test_huge_string_builtins(self, size):
value = '1' + ' ' * size
self.check_huge_string_builtins(value)
@test_support.cpython_only
@unittest.skipUnless(test_support.have_unicode, 'requires unicode support')
@unittest.skipUnless(INT_MAX < PY_SSIZE_T_MAX, "needs UINT_MAX < SIZE_MAX")
@test_support.precisionbigmemtest(size=INT_MAX + 1,
memuse=2*character_size + 7,
dry_run=False)
def test_huge_unicode_builtins(self, size):
value = unicode('1' + ' ' * size)
self.check_huge_string_builtins(value)
def check_huge_string_builtins(self, value):
self.assertRaises(OverflowError, self.interp.tk.getint, value)
self.assertRaises(OverflowError, self.interp.tk.getdouble, value)
self.assertRaises(OverflowError, self.interp.tk.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(): def setUpModule():
if test_support.verbose: if test_support.verbose:
......
...@@ -18,6 +18,9 @@ Core and Builtins ...@@ -18,6 +18,9 @@ Core and Builtins
Library 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 - 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 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 error bubble up as this "bad data" appears in many real world zip files in
......
...@@ -1021,6 +1021,16 @@ statichere PyTypeObject PyTclObject_Type = { ...@@ -1021,6 +1021,16 @@ statichere PyTypeObject PyTclObject_Type = {
0, /*tp_is_gc*/ 0, /*tp_is_gc*/
}; };
#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* static Tcl_Obj*
AsObj(PyObject *value) AsObj(PyObject *value)
{ {
...@@ -1486,6 +1496,7 @@ Tkapp_Eval(PyObject *self, PyObject *args) ...@@ -1486,6 +1496,7 @@ Tkapp_Eval(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:eval", &script)) if (!PyArg_ParseTuple(args, "s:eval", &script))
return NULL; return NULL;
CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1532,6 +1543,7 @@ Tkapp_EvalFile(PyObject *self, PyObject *args) ...@@ -1532,6 +1543,7 @@ Tkapp_EvalFile(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) if (!PyArg_ParseTuple(args, "s:evalfile", &fileName))
return NULL; return NULL;
CHECK_STRING_LENGTH(fileName);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1553,9 +1565,10 @@ Tkapp_Record(PyObject *self, PyObject *args) ...@@ -1553,9 +1565,10 @@ Tkapp_Record(PyObject *self, PyObject *args)
PyObject *res = NULL; PyObject *res = NULL;
int err; int err;
if (!PyArg_ParseTuple(args, "s", &script)) if (!PyArg_ParseTuple(args, "s:record", &script))
return NULL; return NULL;
CHECK_STRING_LENGTH(script);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1576,6 +1589,7 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args) ...@@ -1576,6 +1589,7 @@ Tkapp_AddErrorInfo(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg))
return NULL; return NULL;
CHECK_STRING_LENGTH(msg);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1743,6 +1757,8 @@ SetVar(PyObject *self, PyObject *args, int flags) ...@@ -1743,6 +1757,8 @@ SetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "ssO:setvar", if (!PyArg_ParseTuple(args, "ssO:setvar",
&name1, &name2, &newValue)) &name1, &name2, &newValue))
return NULL; return NULL;
CHECK_STRING_LENGTH(name1);
CHECK_STRING_LENGTH(name2);
/* XXX must hold tcl lock already??? */ /* XXX must hold tcl lock already??? */
newval = AsObj(newValue); newval = AsObj(newValue);
ENTER_TCL ENTER_TCL
...@@ -1788,6 +1804,7 @@ GetVar(PyObject *self, PyObject *args, int flags) ...@@ -1788,6 +1804,7 @@ GetVar(PyObject *self, PyObject *args, int flags)
varname_converter, &name1, &name2)) varname_converter, &name1, &name2))
return NULL; return NULL;
CHECK_STRING_LENGTH(name2);
ENTER_TCL ENTER_TCL
tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP ENTER_OVERLAP
...@@ -1831,6 +1848,8 @@ UnsetVar(PyObject *self, PyObject *args, int flags) ...@@ -1831,6 +1848,8 @@ UnsetVar(PyObject *self, PyObject *args, int flags)
if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2))
return NULL; return NULL;
CHECK_STRING_LENGTH(name1);
CHECK_STRING_LENGTH(name2);
ENTER_TCL ENTER_TCL
code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags); code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags);
ENTER_OVERLAP ENTER_OVERLAP
...@@ -1930,6 +1949,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args) ...@@ -1930,6 +1949,7 @@ Tkapp_ExprString(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprstring", &s)) if (!PyArg_ParseTuple(args, "s:exprstring", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1954,6 +1974,7 @@ Tkapp_ExprLong(PyObject *self, PyObject *args) ...@@ -1954,6 +1974,7 @@ Tkapp_ExprLong(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprlong", &s)) if (!PyArg_ParseTuple(args, "s:exprlong", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
...@@ -1977,6 +1998,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args) ...@@ -1977,6 +1998,7 @@ Tkapp_ExprDouble(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprdouble", &s)) if (!PyArg_ParseTuple(args, "s:exprdouble", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0)
ENTER_TCL ENTER_TCL
...@@ -2001,6 +2023,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args) ...@@ -2001,6 +2023,7 @@ Tkapp_ExprBoolean(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "s:exprboolean", &s)) if (!PyArg_ParseTuple(args, "s:exprboolean", &s))
return NULL; return NULL;
CHECK_STRING_LENGTH(s);
CHECK_TCL_APPARTMENT; CHECK_TCL_APPARTMENT;
ENTER_TCL ENTER_TCL
retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v);
...@@ -2053,6 +2076,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args) ...@@ -2053,6 +2076,7 @@ Tkapp_SplitList(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list)) if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list))
return NULL; return NULL;
CHECK_STRING_LENGTH(list);
if (Tcl_SplitList(Tkapp_Interp(self), list, if (Tcl_SplitList(Tkapp_Interp(self), list,
&argc, &argv) == TCL_ERROR) { &argc, &argv) == TCL_ERROR) {
PyMem_Free(list); PyMem_Free(list);
...@@ -2114,6 +2138,7 @@ Tkapp_Split(PyObject *self, PyObject *args) ...@@ -2114,6 +2138,7 @@ Tkapp_Split(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list)) if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list))
return NULL; return NULL;
CHECK_STRING_LENGTH(list);
v = Split(list); v = Split(list);
PyMem_Free(list); PyMem_Free(list);
return v; return v;
...@@ -2259,6 +2284,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args) ...@@ -2259,6 +2284,7 @@ Tkapp_CreateCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func)) if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func))
return NULL; return NULL;
CHECK_STRING_LENGTH(cmdName);
if (!PyCallable_Check(func)) { if (!PyCallable_Check(func)) {
PyErr_SetString(PyExc_TypeError, "command not callable"); PyErr_SetString(PyExc_TypeError, "command not callable");
return NULL; return NULL;
...@@ -2322,6 +2348,7 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args) ...@@ -2322,6 +2348,7 @@ Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args)
if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName))
return NULL; return NULL;
CHECK_STRING_LENGTH(cmdName);
#ifdef WITH_THREAD #ifdef WITH_THREAD
if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) {
...@@ -3130,6 +3157,10 @@ Tkinter_Create(PyObject *self, PyObject *args) ...@@ -3130,6 +3157,10 @@ Tkinter_Create(PyObject *self, PyObject *args)
&interactive, &wantobjects, &wantTk, &interactive, &wantobjects, &wantTk,
&sync, &use)) &sync, &use))
return NULL; return NULL;
CHECK_STRING_LENGTH(screenName);
CHECK_STRING_LENGTH(baseName);
CHECK_STRING_LENGTH(className);
CHECK_STRING_LENGTH(use);
return (PyObject *) Tkapp_New(screenName, baseName, className, return (PyObject *) Tkapp_New(screenName, baseName, className,
interactive, wantobjects, wantTk, interactive, wantobjects, wantTk,
......
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