From 05a627cc4fb8e6bd610220f466b8b699712307c8 Mon Sep 17 00:00:00 2001 From: Abdullah Masood Date: Mon, 17 Aug 2026 17:15:30 +0500 Subject: [PATCH 1/4] gh-155912: Handle PermissionError from os.sysconf under sandbox --- Lib/concurrent/futures/process.py | 4 ++-- .../test_process_pool.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Lib/concurrent/futures/process.py b/Lib/concurrent/futures/process.py index e3b6c4a5305615..308bb013065364 100644 --- a/Lib/concurrent/futures/process.py +++ b/Lib/concurrent/futures/process.py @@ -700,8 +700,8 @@ def _check_system_limits(): raise NotImplementedError(_system_limited) try: nsems_max = os.sysconf("SC_SEM_NSEMS_MAX") - except (AttributeError, ValueError): - # sysconf not available or setting not available + except (AttributeError, ValueError, OSError): + # sysconf not available, setting not available, or read denied return if nsems_max == -1: # indetermined limit, assume that limit is determined diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index dafbda862c51c2..f6602f48c0640f 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -58,6 +58,24 @@ def test_max_workers_too_large(self): "max_workers must be <= 61"): futures.ProcessPoolExecutor(max_workers=62) + @unittest.skipUnless(hasattr(os, 'sysconf'), 'requires os.sysconf') + def test_sysconf_permission_error(self): + # Issue 155912: ProcessPoolExecutor should handle PermissionError + # from os.sysconf("SC_SEM_NSEMS_MAX") when running under a strict sandbox. + def mock_sysconf(name): + if name == "SC_SEM_NSEMS_MAX": + raise PermissionError(1, "Operation not permitted") + # If it asks for something else, let the real one handle it + # (though normally _check_system_limits only asks for SC_SEM_NSEMS_MAX) + return os_sysconf_orig(name) + + os_sysconf_orig = os.sysconf + with unittest.mock.patch('os.sysconf', side_effect=mock_sysconf): + # Should construct without raising PermissionError + with futures.ProcessPoolExecutor(max_workers=1) as executor: + pass + + @warnings_helper.ignore_fork_in_thread_deprecation_warnings() def test_killed_child(self): # When a child process is abruptly terminated, the whole pool gets From cfc857612bc03edd59be2c27f77dadbddb5cd36e Mon Sep 17 00:00:00 2001 From: Abdullah Masood Date: Mon, 17 Aug 2026 17:19:46 +0500 Subject: [PATCH 2/4] Add NEWS blurb for gh-155912 --- .../next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst diff --git a/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst b/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst new file mode 100644 index 00000000000000..6fb12dd3398c95 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst @@ -0,0 +1 @@ +Handle :exc:`PermissionError` from :func:`os.sysconf` in `concurrent.futures.ProcessPoolExecutor` when running under a strict sandbox. From e3ef07bda8d86119c4f0acd01b829d730be0c0c0 Mon Sep 17 00:00:00 2001 From: Abdullah Masood Date: Mon, 17 Aug 2026 17:24:16 +0500 Subject: [PATCH 3/4] Remove trailing whitespace in test_process_pool.py --- Lib/test/test_concurrent_futures/test_process_pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_concurrent_futures/test_process_pool.py b/Lib/test/test_concurrent_futures/test_process_pool.py index f6602f48c0640f..f6f55526162106 100644 --- a/Lib/test/test_concurrent_futures/test_process_pool.py +++ b/Lib/test/test_concurrent_futures/test_process_pool.py @@ -68,7 +68,7 @@ def mock_sysconf(name): # If it asks for something else, let the real one handle it # (though normally _check_system_limits only asks for SC_SEM_NSEMS_MAX) return os_sysconf_orig(name) - + os_sysconf_orig = os.sysconf with unittest.mock.patch('os.sysconf', side_effect=mock_sysconf): # Should construct without raising PermissionError From a7946adeeddc3d7da203b663777d8b795b866f2c Mon Sep 17 00:00:00 2001 From: Abdullah Masood Date: Mon, 17 Aug 2026 17:26:12 +0500 Subject: [PATCH 4/4] Fix Sphinx lint in NEWS blurb --- .../next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst b/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst index 6fb12dd3398c95..4daa745eb7b3d1 100644 --- a/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst +++ b/Misc/NEWS.d/next/Library/2026-08-17-17-18-00.gh-issue-155912.abcdef.rst @@ -1 +1 @@ -Handle :exc:`PermissionError` from :func:`os.sysconf` in `concurrent.futures.ProcessPoolExecutor` when running under a strict sandbox. +Handle :exc:`PermissionError` from :func:`os.sysconf` in ``concurrent.futures.ProcessPoolExecutor`` when running under a strict sandbox.