Kaydet (Commit) 4203570d authored tarafından Serhiy Storchaka's avatar Serhiy Storchaka

Issue #17119: Fixed integer overflows when processing large Unicode strings

and tuples in the tkinter module.
üst b817faa4
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import unittest import unittest
import sys import sys
import os import os
import _testcapi
from test import test_support from test import test_support
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
...@@ -245,8 +246,22 @@ class TclTest(unittest.TestCase): ...@@ -245,8 +246,22 @@ class TclTest(unittest.TestCase):
self.assertEqual(split(arg), res) self.assertEqual(split(arg), res)
class BigmemTclTest(unittest.TestCase):
def setUp(self):
self.interp = Tcl()
@unittest.skipUnless(_testcapi.INT_MAX < _testcapi.PY_SSIZE_T_MAX,
"needs UINT_MAX < SIZE_MAX")
@test_support.precisionbigmemtest(size=_testcapi.INT_MAX + 1, memuse=5,
dry_run=False)
def test_huge_string(self, size):
value = ' ' * size
self.assertRaises(OverflowError, self.interp.call, 'set', '_', value)
def test_main(): def test_main():
test_support.run_unittest(TclTest, TkinterTest) test_support.run_unittest(TclTest, TkinterTest, BigmemTclTest)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()
...@@ -32,6 +32,9 @@ Core and Builtins ...@@ -32,6 +32,9 @@ Core and Builtins
Library Library
------- -------
- Issue #17119: Fixed integer overflows when processing large Unicode strings
and tuples in the tkinter module.
- Issue #15233: Python now guarantees that callables registered with the atexit - Issue #15233: Python now guarantees that callables registered with the atexit
module will be called in a deterministic order. module will be called in a deterministic order.
......
...@@ -47,6 +47,10 @@ Copyright (C) 1994 Steen Lumholt. ...@@ -47,6 +47,10 @@ Copyright (C) 1994 Steen Lumholt.
#define PyBool_FromLong PyInt_FromLong #define PyBool_FromLong PyInt_FromLong
#endif #endif
#define CHECK_SIZE(size, elemsize) \
((size_t)(size) <= (size_t)INT_MAX && \
(size_t)(size) <= UINT_MAX / (size_t)(elemsize))
/* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, /* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately,
making _tkinter correct for this API means to break earlier making _tkinter correct for this API means to break earlier
versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and
...@@ -378,7 +382,7 @@ Merge(PyObject *args) ...@@ -378,7 +382,7 @@ Merge(PyObject *args)
char **argv = NULL; char **argv = NULL;
int fvStore[ARGSZ]; int fvStore[ARGSZ];
int *fv = NULL; int *fv = NULL;
int argc = 0, fvc = 0, i; Py_ssize_t argc = 0, fvc = 0, i;
char *res = NULL; char *res = NULL;
if (!(tmp = PyList_New(0))) if (!(tmp = PyList_New(0)))
...@@ -400,8 +404,12 @@ Merge(PyObject *args) ...@@ -400,8 +404,12 @@ Merge(PyObject *args)
argc = PyTuple_Size(args); argc = PyTuple_Size(args);
if (argc > ARGSZ) { if (argc > ARGSZ) {
argv = (char **)ckalloc(argc * sizeof(char *)); if (!CHECK_SIZE(argc, sizeof(char *))) {
fv = (int *)ckalloc(argc * sizeof(int)); PyErr_SetString(PyExc_OverflowError, "tuple is too long");
goto finally;
}
argv = (char **)ckalloc((size_t)argc * sizeof(char *));
fv = (int *)ckalloc((size_t)argc * sizeof(int));
if (argv == NULL || fv == NULL) { if (argv == NULL || fv == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
goto finally; goto finally;
...@@ -983,12 +991,18 @@ AsObj(PyObject *value) ...@@ -983,12 +991,18 @@ AsObj(PyObject *value)
else if (PyFloat_Check(value)) else if (PyFloat_Check(value))
return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value)); return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
else if (PyTuple_Check(value)) { else if (PyTuple_Check(value)) {
Tcl_Obj **argv = (Tcl_Obj**) Tcl_Obj **argv;
ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*)); Py_ssize_t size, i;
int i;
size = PyTuple_Size(value);
if (!CHECK_SIZE(size, sizeof(Tcl_Obj *))) {
PyErr_SetString(PyExc_OverflowError, "tuple is too long");
return NULL;
}
argv = (Tcl_Obj **) ckalloc(((size_t)size) * sizeof(Tcl_Obj *));
if(!argv) if(!argv)
return 0; return 0;
for(i=0;i<PyTuple_Size(value);i++) for (i = 0; i < size; i++)
argv[i] = AsObj(PyTuple_GetItem(value,i)); argv[i] = AsObj(PyTuple_GetItem(value,i));
result = Tcl_NewListObj(PyTuple_Size(value), argv); result = Tcl_NewListObj(PyTuple_Size(value), argv);
ckfree(FREECAST argv); ckfree(FREECAST argv);
...@@ -1003,7 +1017,12 @@ AsObj(PyObject *value) ...@@ -1003,7 +1017,12 @@ AsObj(PyObject *value)
#if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3 #if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3
Tcl_UniChar *outbuf = NULL; Tcl_UniChar *outbuf = NULL;
Py_ssize_t i; Py_ssize_t i;
size_t allocsize = ((size_t)size) * sizeof(Tcl_UniChar); size_t allocsize;
if (!CHECK_SIZE(size, sizeof(Tcl_UniChar))) {
PyErr_SetString(PyExc_OverflowError, "string is too long");
return NULL;
}
allocsize = ((size_t)size) * sizeof(Tcl_UniChar);
if (allocsize >= size) if (allocsize >= size)
outbuf = (Tcl_UniChar*)ckalloc(allocsize); outbuf = (Tcl_UniChar*)ckalloc(allocsize);
/* Else overflow occurred, and we take the next exit */ /* Else overflow occurred, and we take the next exit */
...@@ -1198,7 +1217,7 @@ static Tcl_Obj** ...@@ -1198,7 +1217,7 @@ static Tcl_Obj**
Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
{ {
Tcl_Obj **objv = objStore; Tcl_Obj **objv = objStore;
int objc = 0, i; Py_ssize_t objc = 0, i;
if (args == NULL) if (args == NULL)
/* do nothing */; /* do nothing */;
...@@ -1213,7 +1232,11 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) ...@@ -1213,7 +1232,11 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
objc = PyTuple_Size(args); objc = PyTuple_Size(args);
if (objc > ARGSZ) { if (objc > ARGSZ) {
objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *)); if (!CHECK_SIZE(objc, sizeof(Tcl_Obj *))) {
PyErr_SetString(PyExc_OverflowError, "tuple is too long");
return NULL;
}
objv = (Tcl_Obj **)ckalloc(((size_t)objc) * sizeof(Tcl_Obj *));
if (objv == NULL) { if (objv == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
objc = 0; objc = 0;
......
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