diff -r 1079772e7309 Lib/test/test_tcl.py --- a/Lib/test/test_tcl.py Fri May 23 23:58:55 2014 +0300 +++ b/Lib/test/test_tcl.py Sun May 25 10:02:15 2014 +0300 @@ -133,6 +133,47 @@ tcl = self.interp self.assertRaises(TclError,tcl.unsetvar,'a') + def test_getint(self): + tcl = self.interp.tk + self.assertEqual(tcl.getint(' 42 '), 42) + self.assertEqual(tcl.getint(42), 42) + self.assertRaises(TypeError, tcl.getint) + self.assertRaises(TypeError, tcl.getint, '42', '10') + self.assertRaises(TypeError, tcl.getint, b'42') + self.assertRaises(TypeError, tcl.getint, 42.0) + self.assertRaises(TclError, tcl.getint, 'a') + self.assertRaises((ValueError, TclError), tcl.getint, '42\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getint, '42\ud800') + + def test_getdouble(self): + tcl = self.interp.tk + self.assertEqual(tcl.getdouble(' 42 '), 42.0) + self.assertEqual(tcl.getdouble(' 42.5 '), 42.5) + self.assertEqual(tcl.getdouble(42.5), 42.5) + self.assertRaises(TypeError, tcl.getdouble) + self.assertRaises(TypeError, tcl.getdouble, '42.5', '10') + self.assertRaises(TypeError, tcl.getdouble, b'42.5') + self.assertRaises(TypeError, tcl.getdouble, 42) + self.assertRaises(TclError, tcl.getdouble, 'a') + self.assertRaises((ValueError, TclError), tcl.getdouble, '42.5\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getdouble, '42.5\ud800') + + def test_getboolean(self): + tcl = self.interp.tk + self.assertIs(tcl.getboolean('on'), True) + self.assertIs(tcl.getboolean('1'), True) + self.assertEqual(tcl.getboolean(42), 42) + self.assertRaises(TypeError, tcl.getboolean) + self.assertRaises(TypeError, tcl.getboolean, 'on', '1') + self.assertRaises(TypeError, tcl.getboolean, b'on') + self.assertRaises(TypeError, tcl.getboolean, 1.0) + self.assertRaises(TclError, tcl.getboolean, 'a') + self.assertRaises((ValueError, TclError), tcl.getboolean, 'on\0') + self.assertRaises((UnicodeEncodeError, ValueError, TclError), + tcl.getboolean, 'on\ud800') + def testEvalFile(self): tcl = self.interp with open(support.TESTFN, 'w') as f: @@ -521,10 +562,35 @@ @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=2, 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: diff -r 1079772e7309 Modules/_tkinter.c --- a/Modules/_tkinter.c Fri May 23 23:58:55 2014 +0300 +++ b/Modules/_tkinter.c Sun May 25 10:02:15 2014 +0300 @@ -881,6 +881,50 @@ }; +static const char * +bytesAsShortString(PyObject *arg) +{ + const char *s; + if (PyBytes_Size(arg) > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "bytes object is too long"); + return NULL; + } + s = PyBytes_AsString(arg); + if (strlen(s) != PyBytes_Size(arg)) { + PyErr_SetString(PyExc_ValueError, "null byte in bytes object"); + return NULL; + } + return s; +} + +static const char * +unicodeAsShortString(PyObject *arg) +{ + Py_ssize_t size; + const char *s = PyUnicode_AsUTF8AndSize(arg, &size); + if (s == NULL) + return NULL; + if (size > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too long"); + return NULL; + } + if (strlen(s) != size) { + PyErr_SetString(PyExc_ValueError, "null character in string"); + return NULL; + } + return s; +} + +#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) { @@ -1303,6 +1347,7 @@ if (!PyArg_ParseTuple(args, "s:eval", &script)) return NULL; + CHECK_STRING_LENGTH(script); CHECK_TCL_APPARTMENT; ENTER_TCL @@ -1326,6 +1371,7 @@ if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) return NULL; + CHECK_STRING_LENGTH(fileName); CHECK_TCL_APPARTMENT; ENTER_TCL @@ -1346,9 +1392,10 @@ 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 @@ -1369,6 +1416,7 @@ if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) return NULL; + CHECK_STRING_LENGTH(msg); CHECK_TCL_APPARTMENT; ENTER_TCL @@ -1403,35 +1451,19 @@ static int varname_converter(PyObject *in, void *_out) { - char *s; - char **out = (char**)_out; + const char *s; + const char **out = (const char**)_out; if (PyBytes_Check(in)) { - if (PyBytes_Size(in) > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "bytes object is too long"); + s = bytesAsShortString(in); + if (s == NULL) return 0; - } - s = PyBytes_AsString(in); - if (strlen(s) != PyBytes_Size(in)) { - PyErr_SetString(PyExc_ValueError, "null byte in bytes object"); - return 0; - } *out = s; return 1; } if (PyUnicode_Check(in)) { - Py_ssize_t size; - s = PyUnicode_AsUTF8AndSize(in, &size); - if (s == NULL) { + s = unicodeAsShortString(in); + if (s == NULL) return 0; - } - if (size > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, "string is too long"); - return 0; - } - if (strlen(s) != size) { - PyErr_SetString(PyExc_ValueError, "null character in string"); - return 0; - } *out = s; return 1; } @@ -1552,6 +1584,8 @@ 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 @@ -1597,6 +1631,7 @@ varname_converter, &name1, &name2)) return NULL; + CHECK_STRING_LENGTH(name2); ENTER_TCL tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); ENTER_OVERLAP @@ -1639,6 +1674,8 @@ 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 @@ -1672,61 +1709,79 @@ static PyObject * Tkapp_GetInt(PyObject *self, PyObject *args) { - char *s; - int v; - - if (PyTuple_Size(args) == 1) { - PyObject* o = PyTuple_GetItem(args, 0); - if (PyLong_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getint", &arg)) + return NULL; + if (PyLong_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getint", &s)) - return NULL; - if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + int intVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetInt(Tkapp_Interp(self), s, &intVal) == TCL_OK) + return PyLong_FromLong(intVal); return Tkinter_Error(self); - return Py_BuildValue("i", v); + } + PyErr_Format(PyExc_TypeError, + "must be int or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * Tkapp_GetDouble(PyObject *self, PyObject *args) { - char *s; - double v; - - if (PyTuple_Size(args) == 1) { - PyObject *o = PyTuple_GetItem(args, 0); - if (PyFloat_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getdouble", &arg)) + return NULL; + if (PyFloat_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getdouble", &s)) - return NULL; - if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + double doubleVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetDouble(Tkapp_Interp(self), s, &doubleVal) == TCL_OK) + return PyFloat_FromDouble(doubleVal); return Tkinter_Error(self); - return Py_BuildValue("d", v); + } + PyErr_Format(PyExc_TypeError, + "must be double or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * Tkapp_GetBoolean(PyObject *self, PyObject *args) { - char *s; - int v; - - if (PyTuple_Size(args) == 1) { - PyObject *o = PyTuple_GetItem(args, 0); - if (PyLong_Check(o)) { - Py_INCREF(o); - return o; - } + PyObject *arg; + + if (!PyArg_ParseTuple(args, "O:getboolean", &arg)) + return NULL; + if (PyLong_Check(arg)) { + Py_INCREF(arg); + return arg; } - if (!PyArg_ParseTuple(args, "s:getboolean", &s)) - return NULL; - if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) + if (PyUnicode_Check(arg)) { + int intVal; + const char *s = unicodeAsShortString(arg); + if (s == NULL) + return NULL; + if (Tcl_GetBoolean(Tkapp_Interp(self), s, &intVal) == TCL_OK) + return PyBool_FromLong(intVal); return Tkinter_Error(self); - return PyBool_FromLong(v); + } + PyErr_Format(PyExc_TypeError, + "must be int or str, not %.50s", + arg->ob_type->tp_name); + return NULL; } static PyObject * @@ -1739,6 +1794,7 @@ if (!PyArg_ParseTuple(args, "s:exprstring", &s)) return NULL; + CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; ENTER_TCL @@ -1763,6 +1819,7 @@ if (!PyArg_ParseTuple(args, "s:exprlong", &s)) return NULL; + CHECK_STRING_LENGTH(s); CHECK_TCL_APPARTMENT; ENTER_TCL @@ -1786,6 +1843,7 @@ 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 @@ -1810,6 +1868,7 @@ 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); @@ -1865,6 +1924,7 @@ 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); @@ -1926,6 +1986,7 @@ if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list)) return NULL; + CHECK_STRING_LENGTH(list); v = Split(list); PyMem_Free(list); return v; @@ -2057,6 +2118,7 @@ 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; @@ -2118,6 +2180,7 @@ if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) return NULL; + CHECK_STRING_LENGTH(cmdName); #ifdef WITH_THREAD if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { @@ -2789,6 +2852,10 @@ &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,