diff -r 86ddd32068a1 Modules/posixmodule.c --- a/Modules/posixmodule.c Tue Jan 03 11:20:15 2017 +0200 +++ b/Modules/posixmodule.c Fri Jan 06 00:08:31 2017 +0800 @@ -785,7 +785,9 @@ * The length of the path in characters, if specified as * a string. * path.object - * The original object passed in. + * The original object passed in (if get a PathLike object, + * the result of PyOS_FSPath() is treated as the original object). + * Own a reference to the object. * path.cleanup * For internal use only. May point to a temporary object. * (Pay no attention to the man behind the curtain.) @@ -837,23 +839,22 @@ static void path_cleanup(path_t *path) { - if (path->cleanup) { - Py_CLEAR(path->cleanup); - } + Py_CLEAR(path->object); + Py_CLEAR(path->cleanup); } static int path_converter(PyObject *o, void *p) { path_t *path = (path_t *)p; - PyObject *bytes, *to_cleanup = NULL; + PyObject *bytes = NULL; Py_ssize_t length; int is_index, is_buffer, is_bytes, is_unicode; - /* Default to failure, forcing explicit signaling of succcess. */ + /* Default to failure, forcing explicit signaling of success. */ int ret = 0; const char *narrow; #ifdef MS_WINDOWS - PyObject *wo; + PyObject *wo = NULL; const wchar_t *wide; #endif @@ -870,7 +871,9 @@ } /* Ensure it's always safe to call path_cleanup(). */ - path->cleanup = NULL; + path->object = path->cleanup = NULL; + /* path->object owns a reference to the original object */ + Py_INCREF(o); if ((o == Py_None) && path->nullable) { path->wide = NULL; @@ -899,13 +902,13 @@ func = _PyObject_LookupSpecial(o, &PyId___fspath__); if (NULL == func) { - goto error_exit; - } - - o = to_cleanup = _PyObject_CallNoArg(func); + goto error_format; + } + /* still owns a reference to the original object */ + Py_SETREF(o, _PyObject_CallNoArg(func)); Py_DECREF(func); if (NULL == o) { - goto error_exit; + goto error_format; } else if (PyUnicode_Check(o)) { is_unicode = 1; @@ -914,7 +917,7 @@ is_bytes = 1; } else { - goto error_exit; + goto error_format; } } @@ -922,26 +925,27 @@ #ifdef MS_WINDOWS wide = PyUnicode_AsUnicodeAndSize(o, &length); if (!wide) { - goto exit; + goto error_exit; } if (length > 32767) { FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows"); - goto exit; + goto error_exit; } if (wcslen(wide) != length) { FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); - goto exit; + goto error_exit; } path->wide = wide; + path->narrow = False; path->length = length; path->object = o; path->fd = -1; ret = 1; - goto exit; + goto success_exit; #else if (!PyUnicode_FSConverter(o, &bytes)) { - goto exit; + goto error_exit; } #endif } @@ -961,16 +965,16 @@ path->nullable ? "string, bytes, os.PathLike or None" : "string, bytes or os.PathLike", Py_TYPE(o)->tp_name)) { - goto exit; + goto error_exit; } bytes = PyBytes_FromObject(o); if (!bytes) { - goto exit; + goto error_exit; } } else if (is_index) { if (!_fd_converter(o, &path->fd)) { - goto exit; + goto error_exit; } path->wide = NULL; #ifdef MS_WINDOWS @@ -981,10 +985,10 @@ path->length = 0; path->object = o; ret = 1; - goto exit; + goto success_exit; } else { - error_exit: + error_format: PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s", path->function_name ? path->function_name : "", path->function_name ? ": " : "", @@ -995,15 +999,14 @@ path->nullable ? "string, bytes, os.PathLike or None" : "string, bytes or os.PathLike", Py_TYPE(o)->tp_name); - goto exit; + goto error_exit; } length = PyBytes_GET_SIZE(bytes); narrow = PyBytes_AS_STRING(bytes); if ((size_t)length != strlen(narrow)) { FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); - Py_DECREF(bytes); - goto exit; + goto error_exit; } #ifdef MS_WINDOWS @@ -1012,42 +1015,51 @@ length ); if (!wo) { - goto exit; - } - - wide = PyUnicode_AsWideCharString(wo, &length); - Py_DECREF(wo); - + goto error_exit; + } + + wide = PyUnicode_AsUnicodeAndSize(wo, &length); if (!wide) { - goto exit; + goto error_exit; } if (length > 32767) { FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows"); - goto exit; + goto error_exit; } if (wcslen(wide) != length) { FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); - goto exit; + goto error_exit; } path->wide = wide; path->narrow = TRUE; + path->cleanup = wo; + ret = Py_CLEANUP_SUPPORTED; + Py_DECREF(bytes); #else path->wide = NULL; path->narrow = narrow; + if (bytes == o) { + /* Still a reference owned by path->object, don't have to + worry about path->narrow is used after free. */ + Py_DECREF(bytes); + ret = 1; + } + else { + path->cleanup = bytes; + ret = Py_CLEANUP_SUPPORTED; + } #endif path->length = length; path->object = o; path->fd = -1; - if (bytes == o) { - Py_DECREF(bytes); - ret = 1; - } - else { - path->cleanup = bytes; - ret = Py_CLEANUP_SUPPORTED; - } - exit: - Py_XDECREF(to_cleanup); + goto success_exit; + error_exit: + Py_XDECREF(o); + Py_XDECREF(bytes); +#ifdef MS_WINDOWS + Py_XDECREF(wo); +#endif + success_exit: return ret; }