From: Victor Stinner Date: Fri, 23 Sep 2011 16:59:08 +0000 (+0200) Subject: Merge 3.2: Issue #7732: Don't open a directory as a file anymore while X-Git-Tag: v3.3.0a1~1502 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a1fe1f8dcfd43059c38b1493ec67af06fd2afe7f;p=thirdparty%2FPython%2Fcpython.git Merge 3.2: Issue #7732: Don't open a directory as a file anymore while importing a module. Ignore the direcotry if its name matchs the module name (e.g. "__init__.py") and raise a ImportError instead. --- a1fe1f8dcfd43059c38b1493ec67af06fd2afe7f diff --cc Misc/NEWS index 571db4b2f1b2,fd98d021e501..0e18621d2399 --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -283,25 -108,6 +287,25 @@@ Core and Builtin Library ------- +- Issue #9871: Prevent IDLE 3 crash when given byte stings + with invalid hex escape sequences, like b'\x0'. + (Original patch by Claudiu Popa.) + +- Issue #12306: Expose the runtime version of the zlib C library as a constant, + ZLIB_RUNTIME_VERSION, in the zlib module. Patch by Torsten Landschoff. + +- Issue #12959: Add collections.ChainMap to collections.__all__. - ++ +- Issue #8933: distutils' PKG-INFO files and packaging's METADATA files will + now correctly report Metadata-Version: 1.1 instead of 1.0 if a Classifier or + Download-URL field is present. + +- Issue #12567: Add curses.unget_wch() function. Push a character so the next + get_wch() will return it. + +- Issue #9561: distutils and packaging now writes egg-info files using UTF-8, + instead of the locale encoding. + - Issue #8286: The distutils command sdist will print a warning message instead of crashing when an invalid path is given in the manifest template. diff --cc Python/import.c index adfd2cc5df9d,2adcb0467411..24df985d4646 --- a/Python/import.c +++ b/Python/import.c @@@ -1789,282 -1612,232 +1789,291 @@@ find_module_path(PyObject *fullname, Py if (loader != Py_None) { /* a loader was found */ *p_loader = loader; - Py_DECREF(meta_path); - return &importhookdescr; + *p_fd = &importhookdescr; + return 2; } Py_DECREF(loader); + return 0; } - Py_DECREF(meta_path); - } - - if (find_frozen(fullname) != NULL) { - strcpy(buf, fullname); - return &fd_frozen; } + /* no hook was found, use builtin import */ - if (path == NULL) { - if (is_builtin(name)) { - strcpy(buf, name); - return &fd_builtin; - } -#ifdef MS_COREDLL - fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); - if (fp != NULL) { - *p_fp = fp; - return fdp; - } + if (len > 0 && buf[len-1] != SEP +#ifdef ALTSEP + && buf[len-1] != ALTSEP #endif - path = PySys_GetObject("path"); - } - - if (path == NULL || !PyList_Check(path)) { - PyErr_SetString(PyExc_RuntimeError, - "sys.path must be a list of directory names"); - return NULL; - } + ) + buf[len++] = SEP; + Py_UNICODE_strcpy(buf+len, PyUnicode_AS_UNICODE(name)); + len += PyUnicode_GET_SIZE(name); - path_hooks = PySys_GetObject("path_hooks"); - if (path_hooks == NULL || !PyList_Check(path_hooks)) { - PyErr_SetString(PyExc_RuntimeError, - "sys.path_hooks must be a list of " - "import hooks"); - return NULL; - } - 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; - } + filename = PyUnicode_FromUnicode(buf, len); + if (filename == NULL) + return -1; - npath = PyList_Size(path); - namelen = strlen(name); - for (i = 0; i < npath; i++) { - PyObject *v = PyList_GetItem(path, i); - PyObject *origv = v; - const char *base; - Py_ssize_t size; - if (!v) - return NULL; - if (PyUnicode_Check(v)) { - v = PyUnicode_EncodeFSDefault(v); - if (v == NULL) - return NULL; - } - else if (!PyBytes_Check(v)) - continue; - else - Py_INCREF(v); - - base = PyBytes_AS_STRING(v); - size = PyBytes_GET_SIZE(v); - len = size; - if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) { - Py_DECREF(v); - continue; /* Too long */ - } - strcpy(buf, base); - Py_DECREF(v); + /* Check for package import (buf holds a directory name, + and there's an __init__ module in that directory */ +#ifdef HAVE_STAT + if (_Py_stat(filename, &statbuf) == 0 && /* it exists */ + S_ISDIR(statbuf.st_mode)) /* it's a directory */ + { + int match; - if (strlen(buf) != len) { - continue; /* v contains '\0' */ + match = case_ok(filename, 0, name); + if (match < 0) { + Py_DECREF(filename); + return -1; } - - /* sys.path_hooks import hook */ - if (p_loader != NULL) { - PyObject *importer; - - importer = get_path_importer(path_importer_cache, - path_hooks, origv); - if (importer == NULL) { - return NULL; + if (match) { /* case matches */ + if (find_init_module(filename)) { /* and has __init__.py */ + *p_path = filename; + *p_fd = &fd_package; + return 2; } - /* Note: importer is a borrowed reference */ - if (importer != Py_None) { - PyObject *loader; - loader = PyObject_CallMethod(importer, - "find_module", - "s", fullname); - if (loader == NULL) - return NULL; /* error */ - if (loader != Py_None) { - /* a loader was found */ - *p_loader = loader; - return &importhookdescr; + else { + int err; + err = PyErr_WarnFormat(PyExc_ImportWarning, 1, + "Not importing directory %R: missing __init__.py", + filename); + if (err) { + Py_DECREF(filename); + return -1; } - Py_DECREF(loader); - continue; } } - /* no hook was found, use builtin import */ - - if (len > 0 && buf[len-1] != SEP -#ifdef ALTSEP - && buf[len-1] != ALTSEP + } #endif - ) - buf[len++] = SEP; - strcpy(buf+len, name); - len += namelen; + *p_path = filename; + return 1; +} - /* Check for package import (buf holds a directory name, - and there's an __init__ module in that directory */ -#ifdef HAVE_STAT - if (stat(buf, &statbuf) == 0 && /* it exists */ - S_ISDIR(statbuf.st_mode) && /* it's a directory */ - case_ok(buf, len, namelen, name)) { /* case matches */ - if (find_init_module(buf)) { /* and has __init__.py */ - return &fd_package; - } - else { - int err; - PyObject *unicode = PyUnicode_DecodeFSDefault(buf); - if (unicode == NULL) - return NULL; - err = PyErr_WarnFormat(PyExc_ImportWarning, 1, - "Not importing directory '%U': missing __init__.py", - unicode); - Py_DECREF(unicode); - if (err) - return NULL; - } +/* Find a module in search_path_list. For each path, try + find_module_path() or try each _PyImport_Filetab suffix. + + If the module is found, return a file descriptor, write the path in + *p_filename, write the pointer to the file object into *p_fp, and (if + p_loader is not NULL) the loader into *p_loader. + + Otherwise, raise an exception and return NULL. */ + +static struct filedescr* +find_module_path_list(PyObject *fullname, PyObject *name, + PyObject *search_path_list, PyObject *path_hooks, + PyObject *path_importer_cache, + PyObject **p_path, FILE **p_fp, PyObject **p_loader) +{ + Py_ssize_t i, npath; + struct filedescr *fdp = NULL; + char *filemode; + FILE *fp = NULL; + PyObject *prefix, *filename; + int match; + + npath = PyList_Size(search_path_list); + for (i = 0; i < npath; i++) { + PyObject *path; + int ok; + + path = PyList_GetItem(search_path_list, i); + if (path == NULL) + return NULL; + + prefix = NULL; + ok = find_module_path(fullname, name, path, + path_hooks, path_importer_cache, + &prefix, p_loader, &fdp); + if (ok < 0) + return NULL; + if (ok == 0) + continue; + if (ok == 2) { + *p_path = prefix; + return fdp; } -#endif -#if defined(PYOS_OS2) - /* take a snapshot of the module spec for restoration - * after the 8 character DLL hackery - */ - saved_buf = strdup(buf); - saved_len = len; - saved_namelen = namelen; -#endif /* PYOS_OS2 */ + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { + struct stat statbuf; -#if defined(PYOS_OS2) && defined(HAVE_DYNAMIC_LOADING) - /* OS/2 limits DLLs to 8 character names (w/o - extension) - * so if the name is longer than that and its a - * dynamically loaded module we're going to try, - * truncate the name before trying - */ - if (strlen(subname) > 8) { - /* is this an attempt to load a C extension? */ - const struct filedescr *scan; - scan = _PyImport_DynLoadFiletab; - while (scan->suffix != NULL) { - if (!strcmp(scan->suffix, fdp->suffix)) - break; - else - scan++; - } - if (scan->suffix != NULL) { - /* yes, so truncate the name */ - namelen = 8; - len -= strlen(subname) - namelen; - buf[len] = '\0'; - } - } -#endif /* PYOS_OS2 */ - strcpy(buf+len, fdp->suffix); - if (Py_VerboseFlag > 1) - PySys_WriteStderr("# trying %s\n", buf); + filemode = fdp->mode; if (filemode[0] == 'U') filemode = "r" PY_STDIOTEXTMODE; - if (stat(buf, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) - /* it's a directory */ - fp = NULL; - else - fp = fopen(buf, filemode); - if (fp != NULL) { - if (case_ok(buf, len, namelen, name)) - break; - else { /* continue search */ - fclose(fp); - fp = NULL; + filename = PyUnicode_FromFormat("%U%s", prefix, fdp->suffix); + if (filename == NULL) { + Py_DECREF(prefix); + return NULL; + } + + if (Py_VerboseFlag > 1) + PySys_FormatStderr("# trying %R\n", filename); + ++ if (_Py_stat(filename, &statbuf) == 0 && /* it exists */ ++ S_ISDIR(statbuf.st_mode)) /* it's a directory */ ++ { ++ Py_DECREF(filename); ++ continue; ++ } ++ + fp = _Py_fopen(filename, filemode); + if (fp == NULL) { + Py_DECREF(filename); + if (PyErr_Occurred()) { + Py_DECREF(prefix); + return NULL; } + continue; } -#if defined(PYOS_OS2) - /* restore the saved snapshot */ - strcpy(buf, saved_buf); - len = saved_len; - namelen = saved_namelen; -#endif + match = case_ok(filename, -(Py_ssize_t)strlen(fdp->suffix), name); + if (match < 0) { + Py_DECREF(prefix); + Py_DECREF(filename); + return NULL; + } + if (match) { + Py_DECREF(prefix); + *p_path = filename; + *p_fp = fp; + return fdp; + } + Py_DECREF(filename); + + fclose(fp); + fp = NULL; } -#if defined(PYOS_OS2) - /* don't need/want the module name snapshot anymore */ - if (saved_buf) - { - free(saved_buf); - saved_buf = NULL; + Py_DECREF(prefix); + } + PyErr_Format(PyExc_ImportError, + "No module named %R", name); + return NULL; +} + +/* Find a module: + + - try find_module() of each sys.meta_path hook + - try find_frozen() + - try is_builtin() + - try _PyWin_FindRegisteredModule() (Windows only) + - otherwise, call find_module_path_list() with search_path_list (if not + NULL) or sys.path + + fullname can be NULL, but only if p_loader is NULL. + + Return: + + - &fd_builtin (C_BUILTIN) if it is a builtin + - &fd_frozen (PY_FROZEN) if it is frozen + - &fd_package (PKG_DIRECTORY) and write the filename into *p_path + if it is a package + - &importhookdescr (IMP_HOOK) and write the loader into *p_loader if a + importer loader was found + - a file descriptor (PY_SOURCE, PY_COMPILED, C_EXTENSION, PY_RESOURCE or + PY_CODERESOURCE: see _PyImport_Filetab), write the filename into + *p_path and the pointer to the open file into *p_fp + - NULL on error + + By default, *p_path, *p_fp and *p_loader (if set) are set to NULL. + Eg. *p_path is set to NULL for a builtin package. +*/ + +static struct filedescr * +find_module(PyObject *fullname, PyObject *name, PyObject *search_path_list, + PyObject **p_path, FILE **p_fp, PyObject **p_loader) +{ + Py_ssize_t i, npath; + static struct filedescr fd_frozen = {"", "", PY_FROZEN}; + static struct filedescr fd_builtin = {"", "", C_BUILTIN}; + PyObject *path_hooks, *path_importer_cache; + + *p_path = NULL; + *p_fp = NULL; + if (p_loader != NULL) + *p_loader = NULL; + + /* sys.meta_path import hook */ + if (p_loader != NULL) { + PyObject *meta_path; + + meta_path = PySys_GetObject("meta_path"); + if (meta_path == NULL || !PyList_Check(meta_path)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.meta_path must be a list of " + "import hooks"); + return NULL; + } + Py_INCREF(meta_path); /* zap guard */ + npath = PyList_Size(meta_path); + for (i = 0; i < npath; i++) { + PyObject *loader; + PyObject *hook = PyList_GetItem(meta_path, i); + loader = PyObject_CallMethod(hook, "find_module", + "OO", fullname, + search_path_list != NULL ? + search_path_list : Py_None); + if (loader == NULL) { + Py_DECREF(meta_path); + return NULL; /* true error */ + } + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + Py_DECREF(meta_path); + return &importhookdescr; + } + Py_DECREF(loader); } + Py_DECREF(meta_path); + } + + if (find_frozen(fullname) != NULL) + return &fd_frozen; + + if (search_path_list == NULL) { +#ifdef MS_COREDLL + FILE *fp; + struct filedescr *fdp; #endif - if (fp != NULL) - break; + if (is_builtin(name)) + return &fd_builtin; +#ifdef MS_COREDLL + fp = _PyWin_FindRegisteredModule(name, &fdp, p_path); + if (fp != NULL) { + *p_fp = fp; + return fdp; + } + else if (PyErr_Occurred()) + return NULL; +#endif + search_path_list = PySys_GetObject("path"); } - if (fp == NULL) { - PyErr_Format(PyExc_ImportError, - "No module named %.200s", name); + + if (search_path_list == NULL || !PyList_Check(search_path_list)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.path must be a list of directory names"); return NULL; } - *p_fp = fp; - return fdp; + + path_hooks = PySys_GetObject("path_hooks"); + if (path_hooks == NULL || !PyList_Check(path_hooks)) { + PyErr_SetString(PyExc_RuntimeError, + "sys.path_hooks must be a list of " + "import hooks"); + return NULL; + } + 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; + } + + return find_module_path_list(fullname, name, + search_path_list, path_hooks, + path_importer_cache, + p_path, p_fp, p_loader); } -/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) +/* case_bytes(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) * The arguments here are tricky, best shown by example: * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 * ^ ^ ^ ^