Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e695eec

Browse files
author
Charles-François Natali
committed
Issue #13303: Fix a race condition in the bytecode file creation.
1 parent 59142db commit e695eec

2 files changed

Lines changed: 12 additions & 45 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,11 @@ def _write_atomic(path, data):
8585
Be prepared to handle a FileExistsError if concurrent writing of the
8686
temporary file is attempted."""
8787
if not sys.platform.startswith('win'):
88-
# On POSIX-like platforms, renaming is atomic
89-
path_tmp = path + '.tmp'
88+
# On POSIX-like platforms, renaming is atomic. id() is used to generate
89+
# a pseudo-random filename.
90+
path_tmp = '{}.{}'.format(path, id(path))
91+
fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY)
9092
try:
91-
fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY)
9293
with _io.FileIO(fd, 'wb') as file:
9394
file.write(data)
9495
_os.rename(path_tmp, path)

Python/import.c

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,42 +1183,6 @@ parse_source_module(PyObject *pathname, FILE *fp)
11831183
return co;
11841184
}
11851185

1186-
/* Helper to open a bytecode file for writing in exclusive mode */
1187-
1188-
#ifndef MS_WINDOWS
1189-
static FILE *
1190-
open_exclusive(char *filename, mode_t mode)
1191-
{
1192-
#if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC)
1193-
/* Use O_EXCL to avoid a race condition when another process tries to
1194-
write the same file. When that happens, our open() call fails,
1195-
which is just fine (since it's only a cache).
1196-
XXX If the file exists and is writable but the directory is not
1197-
writable, the file will never be written. Oh well.
1198-
*/
1199-
int fd;
1200-
(void) unlink(filename);
1201-
fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC
1202-
#ifdef O_BINARY
1203-
|O_BINARY /* necessary for Windows */
1204-
#endif
1205-
#ifdef __VMS
1206-
, mode, "ctxt=bin", "shr=nil"
1207-
#else
1208-
, mode
1209-
#endif
1210-
);
1211-
if (fd < 0)
1212-
return NULL;
1213-
return fdopen(fd, "wb");
1214-
#else
1215-
/* Best we can do -- on Windows this can't happen anyway */
1216-
return fopen(filename, "wb");
1217-
#endif
1218-
}
1219-
#endif
1220-
1221-
12221186
/* Write a compiled module to a file, placing the time of last
12231187
modification of its source into the header.
12241188
Errors are ignored, if a write error occurs an attempt is made to
@@ -1234,15 +1198,13 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
12341198
#ifdef MS_WINDOWS /* since Windows uses different permissions */
12351199
mode_t mode = srcstat->st_mode & ~S_IEXEC;
12361200
#else
1237-
mode_t mode = srcstat->st_mode & ~S_IXUSR & ~S_IXGRP & ~S_IXOTH;
12381201
mode_t dirmode = (srcstat->st_mode |
12391202
S_IXUSR | S_IXGRP | S_IXOTH |
12401203
S_IWUSR | S_IWGRP | S_IWOTH);
12411204
PyObject *dirbytes;
12421205
#endif
1243-
#ifdef MS_WINDOWS
12441206
int fd;
1245-
#else
1207+
#ifndef MS_WINDOWS
12461208
PyObject *cpathbytes, *cpathbytes_tmp;
12471209
Py_ssize_t cpathbytes_len;
12481210
#endif
@@ -1313,17 +1275,21 @@ write_compiled_module(PyCodeObject *co, PyObject *cpathname,
13131275
return;
13141276
}
13151277
cpathbytes_len = PyBytes_GET_SIZE(cpathbytes);
1316-
cpathbytes_tmp = PyBytes_FromStringAndSize(NULL, cpathbytes_len + 4);
1278+
cpathbytes_tmp = PyBytes_FromStringAndSize(NULL, cpathbytes_len + 6);
13171279
if (cpathbytes_tmp == NULL) {
13181280
Py_DECREF(cpathbytes);
13191281
PyErr_Clear();
13201282
return;
13211283
}
13221284
memcpy(PyBytes_AS_STRING(cpathbytes_tmp), PyBytes_AS_STRING(cpathbytes),
13231285
cpathbytes_len);
1324-
memcpy(PyBytes_AS_STRING(cpathbytes_tmp) + cpathbytes_len, ".tmp", 4);
1286+
memcpy(PyBytes_AS_STRING(cpathbytes_tmp) + cpathbytes_len, "XXXXXX", 6);
13251287

1326-
fp = open_exclusive(PyBytes_AS_STRING(cpathbytes_tmp), mode);
1288+
fd = mkstemp(PyBytes_AS_STRING(cpathbytes_tmp));
1289+
if (0 <= fd)
1290+
fp = fdopen(fd, "wb");
1291+
else
1292+
fp = NULL;
13271293
#endif
13281294
if (fp == NULL) {
13291295
if (Py_VerboseFlag)

0 commit comments

Comments
 (0)