From 23cf403ca17dc1ac2eeccf7476a1ffd47ea88137 Mon Sep 17 00:00:00 2001
From: Benjamin Peterson <benjamin@python.org>
Date: Sun, 30 Mar 2014 19:47:57 -0400
Subject: fix expandtabs overflow detection to be consistent and not rely on
 signed overflow

---
 Objects/stringlib/transmogrify.h | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/Objects/stringlib/transmogrify.h b/Objects/stringlib/transmogrify.h
index 1e132e5..be595a6 100644
--- a/Objects/stringlib/transmogrify.h
+++ b/Objects/stringlib/transmogrify.h
@@ -15,7 +15,7 @@ stringlib_expandtabs(PyObject *self, PyObject *args)
 {
     const char *e, *p;
     char *q;
-    size_t i, j;
+    Py_ssize_t i, j;
     PyObject *u;
     int tabsize = 8;
     
@@ -25,35 +25,31 @@ stringlib_expandtabs(PyObject *self, PyObject *args)
     /* First pass: determine size of output string */
     i = j = 0;
     e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
-    for (p = STRINGLIB_STR(self); p < e; p++)
+    for (p = STRINGLIB_STR(self); p < e; p++) {
         if (*p == '\t') {
             if (tabsize > 0) {
-                j += tabsize - (j % tabsize);
-                if (j > PY_SSIZE_T_MAX) {
-                    PyErr_SetString(PyExc_OverflowError,
-                                    "result is too long");
-                    return NULL;
-                }
+                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' || *p == '\r') {
+                if (i > PY_SSIZE_T_MAX - j)
+                    goto overflow;
                 i += j;
                 j = 0;
-                if (i > PY_SSIZE_T_MAX) {
-                    PyErr_SetString(PyExc_OverflowError,
-                                    "result is too long");
-                    return NULL;
-                }
             }
         }
-    
-    if ((i + j) > PY_SSIZE_T_MAX) {
-        PyErr_SetString(PyExc_OverflowError, "result is too long");
-        return NULL;
     }
     
+    if (i > PY_SSIZE_T_MAX - j)
+        goto overflow;
+    
     /* Second pass: create output string and fill it */
     u = STRINGLIB_NEW(NULL, i + j);
     if (!u)
@@ -62,7 +58,7 @@ stringlib_expandtabs(PyObject *self, PyObject *args)
     j = 0;
     q = STRINGLIB_STR(u);
     
-    for (p = STRINGLIB_STR(self); p < e; p++)
+    for (p = STRINGLIB_STR(self); p < e; p++) {
         if (*p == '\t') {
             if (tabsize > 0) {
                 i = tabsize - (j % tabsize);
@@ -77,8 +73,12 @@ stringlib_expandtabs(PyObject *self, PyObject *args)
             if (*p == '\n' || *p == '\r')
                 j = 0;
         }
-    
+    }
+
     return u;
+  overflow:
+    PyErr_SetString(PyExc_OverflowError, "result too long");
+    return NULL;
 }
 
 Py_LOCAL_INLINE(PyObject *)
-- 
cgit v0.12

