https://github.com/python/cpython/commit/306c556fdbe7034c9a6d87516534eecdb911ad11
commit: 306c556fdbe7034c9a6d87516534eecdb911ad11
branch: main
author: Chris Eibl <[email protected]>
committer: pablogsal <[email protected]>
date: 2026-03-23T23:00:26Z
summary:
gh-144319: obtain SeLockMemoryPrivilege on Windows (#144928)
files:
M Doc/using/cmdline.rst
M Doc/using/configure.rst
M Python/pylifecycle.c
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index ce6872f3c0fda3..73cd8d31d0b20d 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -1132,6 +1132,14 @@ conflict.
and kill the process. Only enable this in environments where the
huge-page pool is properly sized and fork-safety is not a concern.
+ On Windows you need a special privilege. See the
+ `Windows documentation for large pages
+ <https://learn.microsoft.com/windows/win32/memory/large-page-support>`_
+ for details. Python will fail on startup if the required privilege
+ `SeLockMemoryPrivilege
+
<https://learn.microsoft.com/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/lock-pages-in-memory>`_
+ is not held by the user.
+
.. versionadded:: 3.15
diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
index 6bef290d181fc9..084c27d2155d0b 100644
--- a/Doc/using/configure.rst
+++ b/Doc/using/configure.rst
@@ -795,9 +795,18 @@ also be used to improve performance.
Even when compiled with this option, huge pages are **not** used at runtime
unless the :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable is set
- to ``1``. This opt-in is required because huge pages carry risks on Linux:
- if the huge-page pool is exhausted, page faults (including copy-on-write
- faults after :func:`os.fork`) deliver ``SIGBUS`` and kill the process.
+ to ``1``. This opt-in is required because huge pages
+
+ * carry risks on Linux: if the huge-page pool is exhausted, page faults
+ (including copy-on-write faults after :func:`os.fork`) deliver ``SIGBUS``
+ and kill the process.
+
+ * need a special privilege on Windows. See the `Windows documentation for
large pages
+ <https://learn.microsoft.com/windows/win32/memory/large-page-support>`_
+ for details. Python will fail on startup if the required privilege
+ `SeLockMemoryPrivilege
+
<https://learn.microsoft.com/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/lock-pages-in-memory>`_
+ is not held by the user.
The configure script checks that the platform supports ``MAP_HUGETLB``
and emits a warning if it is not available.
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index 68052a91d6a1f1..5da0f3e5be3a70 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -41,6 +41,10 @@
#include "pycore_jit.h" // _PyJIT_Fini()
#endif
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+#include <Windows.h>
+#endif
+
#include "opcode.h"
#include <locale.h> // setlocale()
@@ -486,6 +490,41 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
return _PyStatus_OK();
}
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+static PyStatus
+get_huge_pages_privilege(void)
+{
+ HANDLE hToken;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES |
TOKEN_QUERY, &hToken))
+ {
+ return _PyStatus_ERR("failed to open process token");
+ }
+ TOKEN_PRIVILEGES tp;
+ if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
&tp.Privileges[0].Luid))
+ {
+ CloseHandle(hToken);
+ return _PyStatus_ERR("failed to lookup SeLockMemoryPrivilege for huge
pages");
+ }
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ // AdjustTokenPrivileges can return with nonzero status (i.e. success)
+ // but without having all privileges adjusted (ERROR_NOT_ALL_ASSIGNED).
+ BOOL status = AdjustTokenPrivileges(hToken, FALSE, &tp,
sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+ DWORD error = GetLastError();
+ if (!status || (error != ERROR_SUCCESS))
+ {
+ CloseHandle(hToken);
+ return _PyStatus_ERR(
+ "SeLockMemoryPrivilege not held; "
+ "grant it via Local Security Policy or disable
PYTHON_PYMALLOC_HUGEPAGES");
+ }
+ if (!CloseHandle(hToken))
+ {
+ return _PyStatus_ERR("failed to close process token handle");
+ }
+ return _PyStatus_OK();
+}
+#endif
static PyStatus
pycore_init_runtime(_PyRuntimeState *runtime,
@@ -500,6 +539,15 @@ pycore_init_runtime(_PyRuntimeState *runtime,
return status;
}
+#if defined(PYMALLOC_USE_HUGEPAGES) && defined(MS_WINDOWS)
+ if (runtime->allocators.use_hugepages) {
+ status = get_huge_pages_privilege();
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+ }
+#endif
+
/* Py_Finalize leaves _Py_Finalizing set in order to help daemon
* threads behave a little more gracefully at interpreter shutdown.
* We clobber it here so the new interpreter can start with a clean
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]