[Python-checkins] cpython (2.7): Fixes Issue #14331: Use significantly less stack space when importing modules by

gregory.p.smith python-checkins at python.org
Mon Mar 19 00:14:30 CET 2012


http://hg.python.org/cpython/rev/ad030571e6c0
changeset:   75825:ad030571e6c0
branch:      2.7
parent:      75823:86fb192f38b1
user:        Gregory P. Smith <greg at krypto.org>
date:        Sun Mar 18 16:07:10 2012 -0700
summary:
  Fixes Issue #14331: Use significantly less stack space when importing modules by
allocating path buffers on the heap instead of the stack.

files:
  Misc/NEWS       |    3 +
  Python/import.c |  126 +++++++++++++++++++++++++++--------
  2 files changed, 98 insertions(+), 31 deletions(-)


diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -9,6 +9,9 @@
 Core and Builtins
 -----------------
 
+- Issue #14331: Use significantly less stack space when importing modules by
+  allocating path buffers on the heap instead of the stack.
+
 - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not
   passed strings. Also fix segfaults in the __getattribute__ and __setattr__
   methods of old-style classes.
diff --git a/Python/import.c b/Python/import.c
--- a/Python/import.c
+++ b/Python/import.c
@@ -996,7 +996,7 @@
 {
     struct stat st;
     FILE *fpc;
-    char buf[MAXPATHLEN+1];
+    char *buf;
     char *cpathname;
     PyCodeObject *co;
     PyObject *m;
@@ -1015,6 +1015,10 @@
          */
         st.st_mtime &= 0xFFFFFFFF;
     }
+    buf = PyMem_MALLOC(MAXPATHLEN+1);
+    if (buf == NULL) {
+        return PyErr_NoMemory();
+    }
     cpathname = make_compiled_pathname(pathname, buf,
                                        (size_t)MAXPATHLEN + 1);
     if (cpathname != NULL &&
@@ -1022,9 +1026,9 @@
         co = read_compiled_module(cpathname, fpc);
         fclose(fpc);
         if (co == NULL)
-            return NULL;
+            goto error_exit;
         if (update_compiled_module(co, pathname) < 0)
-            return NULL;
+            goto error_exit;
         if (Py_VerboseFlag)
             PySys_WriteStderr("import %s # precompiled from %s\n",
                 name, cpathname);
@@ -1033,7 +1037,7 @@
     else {
         co = parse_source_module(pathname, fp);
         if (co == NULL)
-            return NULL;
+            goto error_exit;
         if (Py_VerboseFlag)
             PySys_WriteStderr("import %s # from %s\n",
                 name, pathname);
@@ -1046,7 +1050,12 @@
     m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname);
     Py_DECREF(co);
 
+    PyMem_FREE(buf);
     return m;
+
+error_exit:
+    PyMem_FREE(buf);
+    return NULL;
 }
 
 
@@ -1066,7 +1075,7 @@
     PyObject *file = NULL;
     PyObject *path = NULL;
     int err;
-    char buf[MAXPATHLEN+1];
+    char *buf = NULL;
     FILE *fp = NULL;
     struct filedescr *fdp;
 
@@ -1088,8 +1097,13 @@
         err = PyDict_SetItemString(d, "__path__", path);
     if (err != 0)
         goto error;
+    buf = PyMem_MALLOC(MAXPATHLEN+1);
+    if (buf == NULL) {
+        PyErr_NoMemory();
+        goto error;
+    }
     buf[0] = '\0';
-    fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL);
+    fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL);
     if (fdp == NULL) {
         if (PyErr_ExceptionMatches(PyExc_ImportError)) {
             PyErr_Clear();
@@ -1107,6 +1121,8 @@
   error:
     m = NULL;
   cleanup:
+    if (buf)
+        PyMem_FREE(buf);
     Py_XDECREF(path);
     Py_XDECREF(file);
     return m;
@@ -1235,7 +1251,7 @@
     static struct filedescr fd_frozen = {"", "", PY_FROZEN};
     static struct filedescr fd_builtin = {"", "", C_BUILTIN};
     static struct filedescr fd_package = {"", "", PKG_DIRECTORY};
-    char name[MAXPATHLEN+1];
+    char *name;
 #if defined(PYOS_OS2)
     size_t saved_len;
     size_t saved_namelen;
@@ -1249,6 +1265,10 @@
                         "module name is too long");
         return NULL;
     }
+    name = PyMem_MALLOC(MAXPATHLEN+1);
+    if (name == NULL) {
+        return PyErr_NoMemory();
+    }
     strcpy(name, subname);
 
     /* sys.meta_path import hook */
@@ -1260,7 +1280,7 @@
             PyErr_SetString(PyExc_RuntimeError,
                             "sys.meta_path must be a list of "
                             "import hooks");
-            return NULL;
+            goto error_exit;
         }
         Py_INCREF(meta_path);  /* zap guard */
         npath = PyList_Size(meta_path);
@@ -1273,12 +1293,13 @@
                                          path : Py_None);
             if (loader == NULL) {
                 Py_DECREF(meta_path);
-                return NULL;  /* true error */
+                goto error_exit;  /* true error */
             }
             if (loader != Py_None) {
                 /* a loader was found */
                 *p_loader = loader;
                 Py_DECREF(meta_path);
+                PyMem_FREE(name);
                 return &importhookdescr;
             }
             Py_DECREF(loader);
@@ -1292,7 +1313,7 @@
         if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) {
             PyErr_SetString(PyExc_ImportError,
                             "full frozen module name too long");
-            return NULL;
+            goto error_exit;
         }
         strcpy(buf, PyString_AsString(path));
         strcat(buf, ".");
@@ -1300,19 +1321,22 @@
         strcpy(name, buf);
         if (find_frozen(name) != NULL) {
             strcpy(buf, name);
+            PyMem_FREE(name);
             return &fd_frozen;
         }
         PyErr_Format(PyExc_ImportError,
                      "No frozen submodule named %.200s", name);
-        return NULL;
+        goto error_exit;
     }
     if (path == NULL) {
         if (is_builtin(name)) {
             strcpy(buf, name);
+            PyMem_FREE(name);
             return &fd_builtin;
         }
         if ((find_frozen(name)) != NULL) {
             strcpy(buf, name);
+            PyMem_FREE(name);
             return &fd_frozen;
         }
 
@@ -1320,6 +1344,7 @@
         fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen);
         if (fp != NULL) {
             *p_fp = fp;
+            PyMem_FREE(name);
             return fdp;
         }
 #endif
@@ -1328,7 +1353,7 @@
     if (path == NULL || !PyList_Check(path)) {
         PyErr_SetString(PyExc_RuntimeError,
                         "sys.path must be a list of directory names");
-        return NULL;
+        goto error_exit;
     }
 
     path_hooks = PySys_GetObject("path_hooks");
@@ -1336,14 +1361,14 @@
         PyErr_SetString(PyExc_RuntimeError,
                         "sys.path_hooks must be a list of "
                         "import hooks");
-        return NULL;
+        goto error_exit;
     }
     path_importer_cache = PySys_GetObject("path_importer_cache");
     if (path_importer_cache == NULL ||
         !PyDict_Check(path_importer_cache)) {
         PyErr_SetString(PyExc_RuntimeError,
                         "sys.path_importer_cache must be a dict");
-        return NULL;
+        goto error_exit;
     }
 
     npath = PyList_Size(path);
@@ -1352,13 +1377,13 @@
         PyObject *copy = NULL;
         PyObject *v = PyList_GetItem(path, i);
         if (!v)
-            return NULL;
+            goto error_exit;
 #ifdef Py_USING_UNICODE
         if (PyUnicode_Check(v)) {
             copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v),
                 PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL);
             if (copy == NULL)
-                return NULL;
+                goto error_exit;
             v = copy;
         }
         else
@@ -1384,7 +1409,7 @@
                                          path_hooks, v);
             if (importer == NULL) {
                 Py_XDECREF(copy);
-                return NULL;
+                goto error_exit;
             }
             /* Note: importer is a borrowed reference */
             if (importer != Py_None) {
@@ -1394,10 +1419,11 @@
                                              "s", fullname);
                 Py_XDECREF(copy);
                 if (loader == NULL)
-                    return NULL;  /* error */
+                    goto error_exit;  /* error */
                 if (loader != Py_None) {
                     /* a loader was found */
                     *p_loader = loader;
+                    PyMem_FREE(name);
                     return &importhookdescr;
                 }
                 Py_DECREF(loader);
@@ -1421,6 +1447,7 @@
             case_ok(buf, len, namelen, name)) { /* case matches */
             if (find_init_module(buf)) { /* and has __init__.py */
                 Py_XDECREF(copy);
+                PyMem_FREE(name);
                 return &fd_package;
             }
             else {
@@ -1431,7 +1458,7 @@
                 if (PyErr_Warn(PyExc_ImportWarning,
                                warnstr)) {
                     Py_XDECREF(copy);
-                    return NULL;
+                    goto error_exit;
                 }
             }
         }
@@ -1506,10 +1533,15 @@
     if (fp == NULL) {
         PyErr_Format(PyExc_ImportError,
                      "No module named %.200s", name);
-        return NULL;
+        goto error_exit;
     }
     *p_fp = fp;
+    PyMem_FREE(name);
     return fdp;
+
+error_exit:
+    PyMem_FREE(name);
+    return NULL;
 }
 
 /* Helpers for main.c
@@ -2116,7 +2148,7 @@
 import_module_level(char *name, PyObject *globals, PyObject *locals,
                     PyObject *fromlist, int level)
 {
-    char buf[MAXPATHLEN+1];
+    char *buf;
     Py_ssize_t buflen = 0;
     PyObject *parent, *head, *next, *tail;
 
@@ -2130,14 +2162,18 @@
         return NULL;
     }
 
+    buf = PyMem_MALLOC(MAXPATHLEN+1);
+    if (buf == NULL) {
+        return PyErr_NoMemory();
+    }
     parent = get_parent(globals, buf, &buflen, level);
     if (parent == NULL)
-        return NULL;
+        goto error_exit;
 
     head = load_next(parent, level < 0 ? Py_None : parent, &name, buf,
                         &buflen);
     if (head == NULL)
-        return NULL;
+        goto error_exit;
 
     tail = head;
     Py_INCREF(tail);
@@ -2146,7 +2182,7 @@
         Py_DECREF(tail);
         if (next == NULL) {
             Py_DECREF(head);
-            return NULL;
+            goto error_exit;
         }
         tail = next;
     }
@@ -2158,7 +2194,7 @@
         Py_DECREF(head);
         PyErr_SetString(PyExc_ValueError,
                         "Empty module name");
-        return NULL;
+        goto error_exit;
     }
 
     if (fromlist != NULL) {
@@ -2168,16 +2204,22 @@
 
     if (fromlist == NULL) {
         Py_DECREF(tail);
+        PyMem_FREE(buf);
         return head;
     }
 
     Py_DECREF(head);
     if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) {
         Py_DECREF(tail);
-        return NULL;
+        goto error_exit;
     }
 
+    PyMem_FREE(buf);
     return tail;
+
+error_exit:
+    PyMem_FREE(buf);
+    return NULL;
 }
 
 PyObject *
@@ -2567,7 +2609,7 @@
     }
     else {
         PyObject *path, *loader = NULL;
-        char buf[MAXPATHLEN+1];
+        char *buf;
         struct filedescr *fdp;
         FILE *fp = NULL;
 
@@ -2582,11 +2624,16 @@
             }
         }
 
+        buf = PyMem_MALLOC(MAXPATHLEN+1);
+        if (buf == NULL) {
+            return PyErr_NoMemory();
+        }
         buf[0] = '\0';
         fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1,
                           &fp, &loader);
         Py_XDECREF(path);
         if (fdp == NULL) {
+            PyMem_FREE(buf);
             if (!PyErr_ExceptionMatches(PyExc_ImportError))
                 return NULL;
             PyErr_Clear();
@@ -2601,6 +2648,7 @@
             Py_XDECREF(m);
             m = NULL;
         }
+        PyMem_FREE(buf);
     }
 
     return m;
@@ -2618,7 +2666,7 @@
     PyObject *modules = PyImport_GetModuleDict();
     PyObject *path = NULL, *loader = NULL, *existing_m = NULL;
     char *name, *subname;
-    char buf[MAXPATHLEN+1];
+    char *buf;
     struct filedescr *fdp;
     FILE *fp = NULL;
     PyObject *newm;
@@ -2678,6 +2726,11 @@
         if (path == NULL)
             PyErr_Clear();
     }
+    buf = PyMem_MALLOC(MAXPATHLEN+1);
+    if (buf == NULL) {
+        Py_XDECREF(path);
+        return PyErr_NoMemory();
+    }
     buf[0] = '\0';
     fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader);
     Py_XDECREF(path);
@@ -2685,6 +2738,7 @@
     if (fdp == NULL) {
         Py_XDECREF(loader);
         imp_modules_reloading_clear();
+        PyMem_FREE(buf);
         return NULL;
     }
 
@@ -2702,6 +2756,7 @@
         PyDict_SetItemString(modules, name, m);
     }
     imp_modules_reloading_clear();
+    PyMem_FREE(buf);
     return newm;
 }
 
@@ -2832,19 +2887,27 @@
     extern int fclose(FILE *);
     PyObject *fob, *ret;
     struct filedescr *fdp;
-    char pathname[MAXPATHLEN+1];
+    char *pathname;
     FILE *fp = NULL;
 
+    pathname = PyMem_MALLOC(MAXPATHLEN+1);
+    if (pathname == NULL) {
+        return PyErr_NoMemory();
+    }
     pathname[0] = '\0';
     if (path == Py_None)
         path = NULL;
     fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL);
-    if (fdp == NULL)
+    if (fdp == NULL) {
+        PyMem_FREE(pathname);
         return NULL;
+    }
     if (fp != NULL) {
         fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose);
-        if (fob == NULL)
+        if (fob == NULL) {
+            PyMem_FREE(pathname);
             return NULL;
+        }
     }
     else {
         fob = Py_None;
@@ -2853,6 +2916,7 @@
     ret = Py_BuildValue("Os(ssi)",
                   fob, pathname, fdp->suffix, fdp->mode, fdp->type);
     Py_DECREF(fob);
+    PyMem_FREE(pathname);
     return ret;
 }
 

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


More information about the Python-checkins mailing list