Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 84f7020

Browse filesBrowse files
committed
emit a warning if system-wide temporary directory is used
1 parent 453fc7b commit 84f7020
Copy full SHA for 84f7020

File tree

Expand file treeCollapse file tree

2 files changed

+70
-28
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+70
-28
lines changed

‎Lib/multiprocessing/util.py

Copy file name to clipboardExpand all lines: Lib/multiprocessing/util.py
+67-26Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from . import process
2020

2121
__all__ = [
22-
'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
22+
'sub_debug', 'debug', 'info', 'sub_warning', 'warn', 'get_logger',
2323
'log_to_stderr', 'get_temp_dir', 'register_after_fork',
2424
'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
2525
'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING',
@@ -34,6 +34,7 @@
3434
DEBUG = 10
3535
INFO = 20
3636
SUBWARNING = 25
37+
WARNING = 30
3738

3839
LOGGER_NAME = 'multiprocessing'
3940
DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
@@ -53,6 +54,10 @@ def info(msg, *args):
5354
if _logger:
5455
_logger.log(INFO, msg, *args, stacklevel=2)
5556

57+
def warn(msg, *args):
58+
if _logger:
59+
_logger.log(WARNING, msg, *args, stacklevel=2)
60+
5661
def sub_warning(msg, *args):
5762
if _logger:
5863
_logger.log(SUBWARNING, msg, *args, stacklevel=2)
@@ -121,17 +126,17 @@ def is_abstract_socket_namespace(address):
121126
# Function returning a temp directory which will be removed on exit
122127
#
123128

124-
# Maximum length of a socket file path is usually between 92 and 108 [1].
125-
# BSD-based operating systems usually use 104 (OpenBSD, FreeBSD, macOS)
126-
# and Linux uses 108 [2].
129+
# Maximum length of a socket file path is usually between 92 and 108 [1],
130+
# but Linux is known to use a size of 108 [2]. BSD-based systems usually
131+
# use a size of 104 or 108 and Windows does not create AF_UNIX sockets.
127132
#
128133
# [1]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html
129134
# [2]: https://man7.org/linux/man-pages/man7/unix.7.html.
130135

131136
if sys.platform == 'linux':
132-
_SUN_PATH_MAX = 104
133-
elif sys.platform.startswith(('openbsd', 'freebsd')):
134137
_SUN_PATH_MAX = 108
138+
elif sys.platform.startswith(('openbsd', 'freebsd')):
139+
_SUN_PATH_MAX = 104
135140
else:
136141
# On Windows platforms, we do not create AF_UNIX sockets.
137142
_SUN_PATH_MAX = None if os.name == 'nt' else 92
@@ -145,31 +150,67 @@ def _remove_temp_dir(rmtree, tempdir):
145150
if current_process is not None:
146151
current_process._config['tempdir'] = None
147152

153+
def _get_base_temp_dir(tempfile):
154+
"""Get a temporary directory where socket files will be created.
155+
156+
To prevent additional imports, pass a pre-imported 'tempfile' module.
157+
"""
158+
if os.name == 'nt':
159+
return None
160+
# Most of the time, the default temporary directory is /tmp. Thus,
161+
# listener sockets files "$TMPDIR/pymp-XXXXXXXX/sock-XXXXXXXX" do
162+
# not have a path length exceeding SUN_PATH_MAX.
163+
#
164+
# If users specify their own temporary directory, we may be unable
165+
# to create those files. Therefore, we fall back to the system-wide
166+
# temporary directory /tmp, assumed to exist on POSIX systems.
167+
#
168+
# See https://github.com/python/cpython/issues/132124.
169+
base_tempdir = tempfile.gettempdir()
170+
# Files created in a temporary directory are suffixed by a string
171+
# generated by tempfile._RandomNameSequence, which, by design,
172+
# is 8 characters long.
173+
#
174+
# Thus, the length of socket filename will be:
175+
#
176+
# len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX')
177+
sun_path_len = len(base_tempdir) + 14 + 14
178+
if sun_path_len <= _SUN_PATH_MAX:
179+
return base_tempdir
180+
# Fallback to the default system-wide temporary directory.
181+
# This ignores user-defined environment variables.
182+
#
183+
# On POSIX systems, /tmp MUST be writable by any application [1].
184+
# We however emit a warning if this is not the case to prevent
185+
# obscure errors later in the execution.
186+
#
187+
# On some legacy systems, /var/tmp and /usr/tmp can be present
188+
# and will be used instead.
189+
#
190+
# [1]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s18.html
191+
dirlist = ['/tmp', '/var/tmp', '/usr/tmp']
192+
try:
193+
base_system_tempdir = tempfile._get_default_tempdir(dirlist)
194+
except FileNotFoundError:
195+
warn("Process-wide temporary directory %r will not be usable for "
196+
"creating socket files and no usable system-wide temporary "
197+
"directory was found in %r", base_tempdir, dirlist)
198+
# At this point, the system-wide temporary directory is not usable
199+
# but we may assume that the user-defined one is, even if we will
200+
# not be able to write socket files out there.
201+
return base_tempdir
202+
warn("Ignoring user-defined temporary directory: %s", base_tempdir)
203+
# at most max(map(len, dirlist)) + 14 + 14 = 36 characters
204+
assert len(base_system_tempdir) + 14 + 14 <= _SUN_PATH_MAX
205+
return base_system_tempdir
206+
148207
def get_temp_dir():
149208
# get name of a temp directory which will be automatically cleaned up
150209
tempdir = process.current_process()._config.get('tempdir')
151210
if tempdir is None:
152211
import shutil, tempfile
153-
if os.name == 'nt':
154-
tempdir = tempfile.mkdtemp(prefix='pymp-')
155-
else:
156-
# Most of the time, the root temporary directory is /tmp, and thus
157-
# listener sockets files "$TMPDIR/pymp-XXXXXXXX/sock-XXXXXXXX"
158-
# do not have a path length exceeding SUN_PATH_MAX.
159-
#
160-
# If users specify their own temporary directory, we may be unable
161-
# to create those files. Therefore, we fall back to the system-wide
162-
# temporary directory /tmp, assumed to exist on POSIX systems.
163-
#
164-
# See https://github.com/python/cpython/issues/132124.
165-
base_tempdir = tempfile.gettempdir()
166-
# len(base_tempdir) + len('/pymp-XXXXXXXX') + len('/sock-XXXXXXXX')
167-
sun_path_len = len(base_tempdir) + 14 + 14
168-
if sun_path_len > _SUN_PATH_MAX:
169-
# fallback to the system-wide temporary directory,
170-
# ignoring environment variables.
171-
base_tempdir = '/tmp'
172-
tempdir = tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir)
212+
base_tempdir = _get_base_temp_dir(tempfile)
213+
tempdir = tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir)
173214
info('created temp directory %s', tempdir)
174215
# keep a strong reference to shutil.rmtree(), since the finalizer
175216
# can be called late during Python shutdown

‎Lib/tempfile.py

Copy file name to clipboardExpand all lines: Lib/tempfile.py
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def _candidate_tempdir_list():
180180

181181
return dirlist
182182

183-
def _get_default_tempdir():
183+
def _get_default_tempdir(dirlist=None):
184184
"""Calculate the default directory to use for temporary files.
185185
This routine should be called exactly once.
186186
@@ -190,7 +190,8 @@ def _get_default_tempdir():
190190
service, the name of the test file must be randomized."""
191191

192192
namer = _RandomNameSequence()
193-
dirlist = _candidate_tempdir_list()
193+
if dirlist is None:
194+
dirlist = _candidate_tempdir_list()
194195

195196
for dir in dirlist:
196197
if dir != _os.curdir:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.