From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Fri, 10 Oct 2025 21:47:47 +0000 (+0200) Subject: [3.14] gh-139001: Fix thread-safety issue in `pathlib.Path` (gh-139066) (gh-139926) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2660e98b30f83cdba6b52a89e74dfe7de17c1a85;p=thirdparty%2FPython%2Fcpython.git [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 d9b4eef71e7904fbe3a3786a908e493be7debbff) Co-authored-by: Sam Gross --- diff --git a/Lib/pathlib/__init__.py b/Lib/pathlib/__init__.py index 12cf9f579cb3..0d763d1f0dca 100644 --- a/Lib/pathlib/__init__.py +++ b/Lib/pathlib/__init__.py @@ -334,13 +334,8 @@ class PurePath: return paths[0] elif paths: # Join path segments from the initializer. - path = self.parser.join(*paths) - # Cache the joined path. - paths.clear() - paths.append(path) - return path + return self.parser.join(*paths) else: - paths.append('') return '' @property diff --git a/Lib/test/test_pathlib/test_join.py b/Lib/test/test_pathlib/test_join.py index f1a24204b4c3..6b51a09e5ac1 100644 --- a/Lib/test/test_pathlib/test_join.py +++ b/Lib/test/test_pathlib/test_join.py @@ -3,6 +3,8 @@ Tests for pathlib.types._JoinablePath """ import unittest +import threading +from test.support import threading_helper from .support import is_pypi from .support.lexical_path import LexicalPath @@ -158,6 +160,26 @@ class JoinTestBase: parts = p.parts self.assertEqual(parts, (sep, 'a', 'b')) + @threading_helper.requires_working_threading() + def test_parts_multithreaded(self): + P = self.cls + + NUM_THREADS = 10 + NUM_ITERS = 10 + + for _ in range(NUM_ITERS): + b = threading.Barrier(NUM_THREADS) + path = P('a') / 'b' / 'c' / 'd' / 'e' + expected = ('a', 'b', 'c', 'd', 'e') + + def check_parts(): + b.wait() + self.assertEqual(path.parts, expected) + + threads = [threading.Thread(target=check_parts) for _ in range(NUM_THREADS)] + with threading_helper.start_threads(threads): + pass + def test_parent(self): # Relative P = self.cls diff --git a/Misc/NEWS.d/next/Library/2025-09-17-12-07-21.gh-issue-139001.O6tseN.rst b/Misc/NEWS.d/next/Library/2025-09-17-12-07-21.gh-issue-139001.O6tseN.rst new file mode 100644 index 000000000000..3ad5a1272df4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-09-17-12-07-21.gh-issue-139001.O6tseN.rst @@ -0,0 +1,2 @@ +Fix race condition in :class:`pathlib.Path` on the internal ``_raw_paths`` +field.