]> granicus.if.org Git - python/commitdiff
Issue #17119: Fixed integer overflows when processing large Unicode strings
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 21 Aug 2013 18:46:12 +0000 (21:46 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Wed, 21 Aug 2013 18:46:12 +0000 (21:46 +0300)
and tuples in the tkinter module.

Lib/test/test_tcl.py
Misc/NEWS
Modules/_tkinter.c

index 3da87d9b253a685b68b3bad58836311ef7428690..346026236654bf24bc6a2f14ee3457472981bb9d 100644 (file)
@@ -3,6 +3,7 @@
 import unittest
 import sys
 import os
+import _testcapi
 from test import test_support
 from subprocess import Popen, PIPE
 
@@ -245,8 +246,22 @@ class TclTest(unittest.TestCase):
             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():
-    test_support.run_unittest(TclTest, TkinterTest)
+    test_support.run_unittest(TclTest, TkinterTest, BigmemTclTest)
 
 if __name__ == "__main__":
     test_main()
index 83b5116dc41438fe1405c6c33c14d83ef8360819..67853e4e9b9a167d789a86bd55dea8dae049b5dd 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,9 @@ Core and Builtins
 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
   module will be called in a deterministic order.
 
index aed42ac3e4ba7a0588ed1f5ea035a82f302f875b..a04d580b02e404dc139411ec8345d1868e84bb72 100644 (file)
@@ -47,6 +47,10 @@ Copyright (C) 1994 Steen Lumholt.
 #define PyBool_FromLong       PyInt_FromLong
 #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,
    making _tkinter correct for this API means to break earlier
    versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and
@@ -378,7 +382,7 @@ Merge(PyObject *args)
     char **argv = NULL;
     int fvStore[ARGSZ];
     int *fv = NULL;
-    int argc = 0, fvc = 0, i;
+    Py_ssize_t argc = 0, fvc = 0, i;
     char *res = NULL;
 
     if (!(tmp = PyList_New(0)))
@@ -400,8 +404,12 @@ Merge(PyObject *args)
         argc = PyTuple_Size(args);
 
         if (argc > ARGSZ) {
-            argv = (char **)ckalloc(argc * sizeof(char *));
-            fv = (int *)ckalloc(argc * sizeof(int));
+            if (!CHECK_SIZE(argc, sizeof(char *))) {
+                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) {
                 PyErr_NoMemory();
                 goto finally;
@@ -983,12 +991,18 @@ AsObj(PyObject *value)
     else if (PyFloat_Check(value))
         return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value));
     else if (PyTuple_Check(value)) {
-        Tcl_Obj **argv = (Tcl_Obj**)
-            ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*));
-        int i;
+        Tcl_Obj **argv;
+        Py_ssize_t size, 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)
           return 0;
-        for(i=0;i<PyTuple_Size(value);i++)
+        for (i = 0; i < size; i++)
           argv[i] = AsObj(PyTuple_GetItem(value,i));
         result = Tcl_NewListObj(PyTuple_Size(value), argv);
         ckfree(FREECAST argv);
@@ -1003,7 +1017,12 @@ AsObj(PyObject *value)
 #if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3
         Tcl_UniChar *outbuf = NULL;
         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)
             outbuf = (Tcl_UniChar*)ckalloc(allocsize);
         /* Else overflow occurred, and we take the next exit */
@@ -1198,7 +1217,7 @@ static Tcl_Obj**
 Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
 {
     Tcl_Obj **objv = objStore;
-    int objc = 0, i;
+    Py_ssize_t objc = 0, i;
     if (args == NULL)
         /* do nothing */;
 
@@ -1213,7 +1232,11 @@ Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc)
         objc = PyTuple_Size(args);
 
         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) {
                 PyErr_NoMemory();
                 objc = 0;