Skip to content

Commit 2660e98

Browse files
[3.14] gh-139001: Fix thread-safety issue in pathlib.Path (gh-139066) (gh-139926)
Don't cache the joined path in `_raw_path` because the caching isn't thread safe. (cherry picked from commit d9b4eef) Co-authored-by: Sam Gross <[email protected]>
1 parent 7ea79f6 commit 2660e98

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

Lib/pathlib/__init__.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,8 @@ def _raw_path(self):
334334
return paths[0]
335335
elif paths:
336336
# Join path segments from the initializer.
337-
path = self.parser.join(*paths)
338-
# Cache the joined path.
339-
paths.clear()
340-
paths.append(path)
341-
return path
337+
return self.parser.join(*paths)
342338
else:
343-
paths.append('')
344339
return ''
345340

346341
@property

Lib/test/test_pathlib/test_join.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
"""
44

55
import unittest
6+
import threading
7+
from test.support import threading_helper
68

79
from .support import is_pypi
810
from .support.lexical_path import LexicalPath
@@ -158,6 +160,26 @@ def test_parts(self):
158160
parts = p.parts
159161
self.assertEqual(parts, (sep, 'a', 'b'))
160162

163+
@threading_helper.requires_working_threading()
164+
def test_parts_multithreaded(self):
165+
P = self.cls
166+
167+
NUM_THREADS = 10
168+
NUM_ITERS = 10
169+
170+
for _ in range(NUM_ITERS):
171+
b = threading.Barrier(NUM_THREADS)
172+
path = P('a') / 'b' / 'c' / 'd' / 'e'
173+
expected = ('a', 'b', 'c', 'd', 'e')
174+
175+
def check_parts():
176+
b.wait()
177+
self.assertEqual(path.parts, expected)
178+
179+
threads = [threading.Thread(target=check_parts) for _ in range(NUM_THREADS)]
180+
with threading_helper.start_threads(threads):
181+
pass
182+
161183
def test_parent(self):
162184
# Relative
163185
P = self.cls
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix race condition in :class:`pathlib.Path` on the internal ``_raw_paths``
2+
field.

0 commit comments

Comments
 (0)