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]

Reply via email to