[Python-checkins] cpython (2.7): fix overflow detection of strop.expandtabs

benjamin.peterson python-checkins at python.org
Mon Mar 31 02:10:10 CEST 2014


http://hg.python.org/cpython/rev/5dabc2d2f776
changeset:   90061:5dabc2d2f776
branch:      2.7
parent:      90056:a2254f4338e6
user:        Benjamin Peterson <benjamin at python.org>
date:        Sun Mar 30 20:09:44 2014 -0400
summary:
  fix overflow detection of strop.expandtabs

files:
  Lib/test/test_strop.py |   6 ++++++
  Misc/NEWS              |   3 +++
  Modules/stropmodule.c  |  28 +++++++++++++++-------------
  3 files changed, 24 insertions(+), 13 deletions(-)


diff --git a/Lib/test/test_strop.py b/Lib/test/test_strop.py
--- a/Lib/test/test_strop.py
+++ b/Lib/test/test_strop.py
@@ -4,6 +4,7 @@
                         r'test.test_strop|unittest')
 import strop
 import unittest
+import sys
 from test import test_support
 
 
@@ -115,6 +116,11 @@
         strop.uppercase
         strop.whitespace
 
+    @unittest.skipUnless(sys.maxsize == 2147483647, "only for 32-bit")
+    def test_expandtabs_overflow(self):
+        s = '\t\n' * 0x10000 + 'A' * 0x1000000
+        self.assertRaises(OverflowError, strop.expandtabs, s, 0x10001)
+
     @test_support.precisionbigmemtest(size=test_support._2G - 1, memuse=5)
     def test_stropjoin_huge_list(self, size):
         a = "A" * size
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -40,6 +40,9 @@
 Library
 -------
 
+- Fix possible overflow bug in strop.expandtabs. You shouldn't be using this
+  module!
+
 - Issue #20145: `assertRaisesRegex` now raises a TypeError if the second
   argument is not a string or compiled regex.
 
diff --git a/Modules/stropmodule.c b/Modules/stropmodule.c
--- a/Modules/stropmodule.c
+++ b/Modules/stropmodule.c
@@ -593,7 +593,7 @@
     char* e;
     char* p;
     char* q;
-    Py_ssize_t i, j, old_j;
+    Py_ssize_t i, j;
     PyObject* out;
     char* string;
     Py_ssize_t stringlen;
@@ -610,30 +610,29 @@
     }
 
     /* First pass: determine size of output string */
-    i = j = old_j = 0; /* j: current column; i: total of previous lines */
+    i = j = 0; /* j: current column; i: total of previous lines */
     e = string + stringlen;
     for (p = string; p < e; p++) {
         if (*p == '\t') {
-            j += tabsize - (j%tabsize);
-            if (old_j > j) {
-                PyErr_SetString(PyExc_OverflowError,
-                                "new string is too long");
-                return NULL;
-            }
-            old_j = j;
+            Py_ssize_t incr = tabsize - (j%tabsize);
+            if (j > PY_SSIZE_T_MAX - incr)
+                goto overflow;
+            j += incr;
         } else {
+            if (j > PY_SSIZE_T_MAX - 1)
+                goto overflow;
             j++;
             if (*p == '\n') {
+                if (i > PY_SSIZE_T_MAX - j)
+                    goto overflow;
                 i += j;
                 j = 0;
             }
         }
     }
 
-    if ((i + j) < 0) {
-        PyErr_SetString(PyExc_OverflowError, "new string is too long");
-        return NULL;
-    }
+    if (i > PY_SSIZE_T_MAX - j)
+        goto overflow;
 
     /* Second pass: create output string and fill it */
     out = PyString_FromStringAndSize(NULL, i+j);
@@ -658,6 +657,9 @@
     }
 
     return out;
+  overflow:
+    PyErr_SetString(PyExc_OverflowError, "result is too long");
+    return NULL;
 }
 
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list