Changing the access property of a large memory page, by 2 calls to VirtualAlloc: fails

PIERRE REISS LABORDE 101 Reputation points
2022-11-24T16:49:23.357+00:00

The first test uses VirtualAlloc on a 2Mb page of writecombine type. A second VirtualAlloc attempts the switch of this page to shared type. It fails with error ERROR_INVALID_ADDRESS:
(The "lock pages in memory" privilege is assigned to my account, which owns administrator rights.)

#include "windows.h"  
#include "stdio.h"  
  
int main ()  
  {  
  TOKEN_PRIVILEGES ToPri;  
  LUID             Luid;  
  HANDLE           hToken;  
  LPVOID           Base, Page;  
  SIZE_T           Large = 0x200000;  
  int              *Pin;  
  
  if ( !OpenProcessToken (  
         GetCurrentProcess (),  
         TOKEN_ADJUST_PRIVILEGES,  
         &hToken ) )  
    { printf ( "hToken fails\n" );   return 1; }  
  
  if ( !LookupPrivilegeValue (  
         NULL,  
         "SeLockMemoryPrivilege",  
         &Luid ) )  
    { printf ( "Lookup fails\n" );   return 2; }  
  
  ToPri.PrivilegeCount = 1;  
  ToPri.Privileges[0].Luid = Luid;  
  ToPri.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;  
  if ( !AdjustTokenPrivileges (  
         hToken,  
         FALSE,  
         &ToPri,  
         0,  
         (PTOKEN_PRIVILEGES) NULL,  
         (PDWORD) NULL ) )  
    { printf ( "Adjust fails\n" );   return 3; }  
  if ( GetLastError () == ERROR_NOT_ALL_ASSIGNED )  
    { printf ( "token without privilege\n" );   return 4; }  
  
  Base = VirtualAlloc (  
           0,  
           Large,  
           MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES,  
           PAGE_READWRITE | PAGE_WRITECOMBINE );  
  if ( !Base )  
    { printf ( "1st VirtualAlloc fails\n" );   return 5; }  
  Pin  = (int*) Base;  
  *Pin = 22197;  
  MemoryBarrier ();  
  
  Page = VirtualAlloc (  
           Base,  
           Large,  
           MEM_COMMIT,  
           PAGE_READWRITE );  
  if ( Pin != (int*) Page   ||   *Pin != 22197 )  
    { printf ( "Page=%p   Err=%d\n", Page, GetLastError () );   return 6; }  
  
  VirtualFree ( Base, 0, MEM_RELEASE );  
  printf ( "normal end\n" );  
  return 0;  
  }  

The output is:
Page=0000000000000000 Err=487

The second test is similar, but it uses a 4Kb page instead. It runs normally:

#include "windows.h"  
#include "stdio.h"  
  
int main ()  
  {  
  LPVOID Base, Page;  
  SIZE_T Normal = 0x1000;  
  int    *Pin;  
  
  Base = VirtualAlloc ( 0, Normal,  
                        MEM_RESERVE | MEM_COMMIT,  
                        PAGE_READWRITE | PAGE_WRITECOMBINE );  
  if ( !Base )   return 1;  
  Pin  = (int*) Base;  
  *Pin = 22197;  
  MemoryBarrier ();  
  
  Page = VirtualAlloc ( Base, Normal,  
                        MEM_COMMIT,  
                        PAGE_READWRITE );  
  if ( Pin != (int*) Page   ||   *Pin != 22197 )   return 2;  
  
  VirtualFree ( Base, 0, MEM_RELEASE );  
  printf ( "normal end\n" );  
  return 0;  
  }  

The output is:
normal end

MemoryBarrier acts as a fencing operation, insuring that *Pin after the 2nd VirtualAlloc is not read before the store into memory is completed.

According to the MSDN doc, "VirtualAlloc can commit a page that is already committed. This means you can commit a range of pages, regardless of whether they have already been committed, and the function will not fail." That seems to apply to large pages.

My processor is an Intel Broadwell Core i7 5600U.
I use Visual Studio 2019 version 14.29.30133 and Windows Kits version 10.0.22000.0, under Windows10 version 21H2.

Is this problem a permanent restriction in the case of large pages? Or is it related
to the Intel chip capabilities, when changing the properties of a page? Or something else? Thanks by advance!

Windows development | Windows API - Win32
Windows for business | Windows Client for IT Pros | User experience | Other
Developer technologies | C++
{count} votes

2 answers

Sort by: Most helpful
  1. Xiaopo Yang - MSFT 12,731 Reputation points Microsoft External Staff
    2022-11-28T07:06:01.557+00:00

    The behavior, which the document doesn't mention, could be Large-Page Limitation and by design.

    0 comments No comments

  2. PIERRE REISS LABORDE 101 Reputation points
    2022-12-04T16:02:46.147+00:00

    That's clear. I accept the answer. Thank you.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.