summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles-François Natali <neologix@free.fr>2011-10-31 19:47:31 (GMT)
committerCharles-François Natali <neologix@free.fr>2011-10-31 19:47:31 (GMT)
commite695eec24addd2a39c9af7456b8218c0810d742c (patch)
treef6e5c0cbb2aaa4d6a3ddbec9425fda2e4d885c12
parent59142db6d35f00142cd9982878e75d43cbda7a68 (diff)
downloadcpython-e695eec24addd2a39c9af7456b8218c0810d742c.zip
cpython-e695eec24addd2a39c9af7456b8218c0810d742c.tar.gz
cpython-e695eec24addd2a39c9af7456b8218c0810d742c.tar.bz2
Issue #13303: Fix a race condition in the bytecode file creation.
-rw-r--r--Lib/importlib/_bootstrap.py7
-rw-r--r--Python/import.c50
2 files changed, 12 insertions, 45 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 4161b3e..775fa85 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -85,10 +85,11 @@ def _write_atomic(path, data):
Be prepared to handle a FileExistsError if concurrent writing of the
temporary file is attempted."""
if not sys.platform.startswith('win'):
- # On POSIX-like platforms, renaming is atomic
- path_tmp = path + '.tmp'
+ # On POSIX-like platforms, renaming is atomic. id() is used to generate
+ # a pseudo-random filename.
+ path_tmp = '{}.{}'.format(path, id(path))
+ fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY)
try:
- fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY)
with _io.FileIO(fd, 'wb') as file:
file.write(data)
_os.rename(path_tmp, path)
diff --git a/Python/import.c b/Python/import.c
index 03e9986..701041b 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -1183,42 +1183,6 @@ parse_source_module(PyObject *pathname, FILE *fp)
return co;
}
-/* Helper to open a bytecode file for writing in exclusive mode */
-
-#ifndef MS_WINDOWS
-static FILE *
-open_exclusive(char *filename, mode_t mode)
-{
-#if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
- /* Use O_EXCL to avoid a race condition when another process tries to
- write the same file. When that happens, our open() call fails,
- which is just fine (since it's only a cache).
- XXX If the file exists and is writable but the directory is not
- writable, the file will never be written. Oh well.
- */
- int fd;
- (void) unlink(filename);
- fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC
-#ifdef O_BINARY
- |O_BINARY /* necessary for Windows */
-#endif
-#ifdef __VMS
- , mode, "ctxt=bin", "shr=nil"
-#else
- , mode
-#endif
- );
- if (fd < 0)
- return NULL;
- return fdopen(fd, "wb");
-#else
- /* Best we can do -- on Windows this can't happen anyway */
- return fopen(filename, "wb");
-#endif
-}
-#endif
-
-
/* Write a compiled module to a file, placing the time of last
modification of its source into the header.
Errors are ignored, if a write error occurs an attempt is made to
@@ -1234,15 +1198,13 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
#ifdef MS_WINDOWS /* since Windows uses different permissions */
mode_t mode = srcstat->st_mode & ~S_IEXEC;
#else
- mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
mode_t dirmode = (srcstat->st_mode |
S_IXUSR | S_IXGRP | S_IXOTH |
S_IWUSR | S_IWGRP | S_IWOTH);
PyObject *dirbytes;
#endif
-#ifdef MS_WINDOWS
int fd;
-#else
+#ifndef MS_WINDOWS
PyObject *cpathbytes, *cpathbytes_tmp;
Py_ssize_t cpathbytes_len;
#endif
@@ -1313,7 +1275,7 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
return;
}
cpathbytes_len = PyBytes_GET_SIZE(cpathbytes);
- cpathbytes_tmp = PyBytes_FromStringAndSize(NULL, cpathbytes_len + 4);
+ cpathbytes_tmp = PyBytes_FromStringAndSize(NULL, cpathbytes_len + 6);
if (cpathbytes_tmp == NULL) {
Py_DECREF(cpathbytes);
PyErr_Clear();
@@ -1321,9 +1283,13 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
}
memcpy(PyBytes_AS_STRING(cpathbytes_tmp), PyBytes_AS_STRING(cpathbytes),
cpathbytes_len);
- memcpy(PyBytes_AS_STRING(cpathbytes_tmp) + cpathbytes_len, ".tmp", 4);
+ memcpy(PyBytes_AS_STRING(cpathbytes_tmp) + cpathbytes_len, "XXXXXX", 6);
- fp = open_exclusive(PyBytes_AS_STRING(cpathbytes_tmp), mode);
+ fd = mkstemp(PyBytes_AS_STRING(cpathbytes_tmp));
+ if (0 <= fd)
+ fp = fdopen(fd, "wb");
+ else
+ fp = NULL;
#endif
if (fp == NULL) {
if (Py_VerboseFlag)