如何解决合并 Win32 的虚拟分配占位符
我试图围绕 Win32 的虚拟分配概念占位符以及如何合并它们。
不幸的是,我在网上找不到任何示例,尽管尝试了各种变体,但我的代码仍无法正常工作。
有人能指出我遗漏的地方吗?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// Helpers
// -------------------------------------------------------------------------
static void
get_page_size(size_t *page_size)
{
SYstem_INFO system_info;
GetSystemInfo(&system_info);
*page_size = system_info.dwPageSize;
}
static void
touch_pages(void *buf,size_t size,size_t page_size)
{
size_t i;
for (i = 0; i < size; i += page_size) {
void *ptr;
ptr = (void *)((uintptr_t)buf + i);
*((size_t *)ptr) = i;
}
}
static void
check_pages(void *buf,size_t page_size)
{
size_t i;
size_t good;
good = 0;
for (i = 0; i < size; i += page_size) {
void *ptr;
ptr = (void *)((uintptr_t)buf + i);
if (*((size_t *)ptr) != i) {
printf("invalid data!\n");
exit(0);
}
++good;
}
printf("all good!\n");
}
static void
print_last_error(void)
{
char buf[256];
FormatMessageA(
FORMAT_MESSAGE_FROM_SYstem | FORMAT_MESSAGE_IGnorE_INSERTS,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),buf,(sizeof(buf) / sizeof(char)),NULL);
printf("%s\n",buf);
}
// -------------------------------------------------------------------------
int
main(void)
{
size_t page_size;
ULARGE_INTEGER alloc_size;
get_page_size(&page_size);
alloc_size.QuadPart = 0x10000000;
// PART 1
// -------------------------------------------------------------------------
// Allocate 256 MB at a fixed address.
// This is done by reserving a block of virtual addresses,creating
// paging-backed sections,and mapping them onto the allocation block.
void *addr_1 = (void *)0x10000000; // Aligned with allocation granularity.
void *placeholder_1 = VirtualAlloc2(
GetCurrentProcess(),addr_1,(size_t)alloc_size.QuadPart,MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,PAGE_NOACCESS,0
);
if (placeholder_1 == NULL) {
printf("placeholder_1: VirtualAlloc2 Failed\n");
print_last_error();
exit(0);
}
HANDLE section_1 = CreateFileMappingA(
INVALID_HANDLE_VALUE,PAGE_READWRITE,alloc_size.HighPart,alloc_size.LowPart,NULL
);
if (section_1 == NULL) {
printf("section_1: CreateFileMappingA Failed\n");
print_last_error();
exit(0);
}
void *view_1 = MapViewOfFile3(
section_1,GetCurrentProcess(),MEM_REPLACE_PLACEHOLDER,0
);
if (view_1 == NULL) {
printf("view_1: MapViewOfFile3 Failed\n");
print_last_error();
exit(0);
}
// Touch each page just to make sure that they are fully committed.
touch_pages(view_1,page_size);
// PART 2
// -------------------------------------------------------------------------
// Grow the prevIoUs allocation by another 256 MB.
// The exercise here is to try replicating Linux's `mremap()` by using
// `MEM_COALESCE_PLACEHOLDERS`.
// The idea is to reserve another block of virtual addresses just after
// the first allocation block,merging both blocks into a single one,// creating another bunch of paging-backed sections,and mapping
// all the pages onto the merged allocation block.
void *addr_2 = (void *)0x20000000; // Aligned with allocation granularity.
void *placeholder_2 = VirtualAlloc2(
GetCurrentProcess(),addr_2,0
);
if (placeholder_2 == NULL) {
printf("placeholder_2: VirtualAlloc2 Failed\n");
print_last_error();
exit(0);
}
// It seems that we first need to unmap or else the following call to
// `VirtualFree()` complains about attempting to access an invalid address.
if (!UnmapViewOfFile2(
GetCurrentProcess(),view_1,MEM_PRESERVE_PLACEHOLDER
))
{
printf("view_1: UnmapViewOfFile2 Failed\n");
print_last_error();
exit(0);
}
if (!VirtualFree(
placeholder_1,(size_t)alloc_size.QuadPart * 2,MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS
))
{
printf("placeholder_1: VirtualFree Failed\n");
print_last_error();
exit(0);
}
// Create a new allocation block that represents both prevIoUs blocks
// merged into a single one.
void *placeholder_3 = VirtualAlloc2(
GetCurrentProcess(),MEM_RESERVE | MEM_REPLACE_PLACEHOLDER,0
);
if (placeholder_3 == NULL) {
printf("placeholder_3: VirtualAlloc2 Failed\n");
print_last_error();
exit(0);
}
HANDLE section_2 = CreateFileMappingA(
INVALID_HANDLE_VALUE,NULL
);
if (section_2 == NULL) {
printf("section_2: CreateFileMappingA Failed\n");
print_last_error();
exit(0);
}
// This fails due to an attempt to access an invalid addres.
void *view_1b = MapViewOfFile3(
section_1,0
);
if (view_1b == NULL) {
printf("view_1b: MapViewOfFile3 Failed\n");
print_last_error();
exit(0);
}
// This fails for the same reason if the prevIoUs mapping is commented.
void *view_2b = MapViewOfFile3(
section_2,0
);
if (view_2b == NULL) {
printf("view_2b: MapViewOfFile3 Failed\n");
print_last_error();
exit(0);
}
// Check that we have the same data as the one we touched.
check_pages(view_1,page_size);
return 0;
}
解决方法
根据VirtualAlloc2,MEM_REPLACE_PLACEHOLDER
AllocationType 将占位符替换为普通的私有分配。所以只需注释 placeholder_3
行。替换占位符后不能MapViewOfFile3
。
以下代码适用于我。
int
main(void)
{
size_t page_size;
ULARGE_INTEGER alloc_size{};
get_page_size(&page_size);
//alloc_size.QuadPart = page_size;
alloc_size.QuadPart = 0x10000000;
// PART 1
// -------------------------------------------------------------------------
// Allocate 256 MB at a fixed address.
// This is done by reserving a block of virtual addresses,creating
// paging-backed sections,and mapping them onto the allocation block.
void* addr_1 = (void*)0x10000000; // Aligned with allocation granularity.
void* placeholder_1 = VirtualAlloc2(
GetCurrentProcess(),addr_1,(size_t)alloc_size.QuadPart,MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,PAGE_NOACCESS,NULL,0
);
if (placeholder_1 == NULL) {
printf("placeholder_1: VirtualAlloc2 failed\n");
print_last_error();
exit(0);
}
HANDLE section_1 = CreateFileMappingA(
INVALID_HANDLE_VALUE,PAGE_READWRITE,alloc_size.HighPart,alloc_size.LowPart,NULL
);
if (section_1 == NULL) {
printf("section_1: CreateFileMappingA failed\n");
print_last_error();
exit(0);
}
void* view_1 = MapViewOfFile3(
section_1,GetCurrentProcess(),MEM_REPLACE_PLACEHOLDER,0
);
if (view_1 == NULL) {
printf("view_1: MapViewOfFile3 failed\n");
print_last_error();
exit(0);
}
// Touch each page just to make sure that they are fully committed.
//touch_pages(view_1,page_size);
// PART 2
// -------------------------------------------------------------------------
// Grow the previous allocation by another 256 MB.
// The exercise here is to try replicating Linux's `mremap()` by using
// `MEM_COALESCE_PLACEHOLDERS`.
// The idea is to reserve another block of virtual addresses just after
// the first allocation block,merging both blocks into a single one,// creating another bunch of paging-backed sections,and mapping
// all the pages onto the merged allocation block.
//void* addr_2 = (void*)((PCHAR)addr_1 + alloc_size.QuadPart); // Aligned with allocation granularity.
void* addr_2 = (void*)0x20000000; // Aligned with allocation granularity.
void* placeholder_2 = VirtualAlloc2(
GetCurrentProcess(),addr_2,0
);
if (placeholder_2 == NULL) {
printf("placeholder_2: VirtualAlloc2 failed\n");
print_last_error();
exit(0);
}
// It seems that we first need to unmap or else the following call to
// `VirtualFree()` complains about attempting to access an invalid address.
if (!UnmapViewOfFile2(
GetCurrentProcess(),view_1,MEM_PRESERVE_PLACEHOLDER
))
{
printf("view_1: UnmapViewOfFile2 failed\n");
print_last_error();
exit(0);
}
alloc_size.QuadPart *= 2;
if (!VirtualFree(
addr_1,MEM_RELEASE |MEM_COALESCE_PLACEHOLDERS
))
{
printf("placeholder_1: VirtualFree failed\n");
print_last_error();
exit(0);
}
// Create a new allocation block that represents both previous blocks
// merged into a single one.
/*void* placeholder_3 = VirtualAlloc2(
GetCurrentProcess(),MEM_RESERVE | MEM_REPLACE_PLACEHOLDER,0
);
if (placeholder_3 == NULL) {
printf("placeholder_3: VirtualAlloc2 failed\n");
print_last_error();
exit(0);
}*/
HANDLE section_2 = CreateFileMappingA(
INVALID_HANDLE_VALUE,NULL
);
if (section_2 == NULL) {
printf("section_2: CreateFileMappingA failed\n");
print_last_error();
exit(0);
}
// This fails due to an attempt to access an invalid addres.
void* view_1b = MapViewOfFile3(
section_2,0
);
if (view_1b == NULL) {
printf("view_1b: MapViewOfFile3 failed\n");
print_last_error();
exit(0);
}
char* lpPtr = (char*)view_1b;
lpPtr[0x20000000 - 1] = 'a';
//// This fails for the same reason if the previous mapping is commented.
//void* view_2b = MapViewOfFile3(
// section_2,// GetCurrentProcess(),// addr_2,// 0,// (size_t)alloc_size.QuadPart,// MEM_REPLACE_PLACEHOLDER,// PAGE_READWRITE,// NULL,// 0
//);
//if (view_2b == NULL) {
// printf("view_2b: MapViewOfFile3 failed\n");
// print_last_error();
// exit(0);
//}
return 0;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。