Index: sandbox/win/src/sandbox_nt_util.cc |
diff --git a/sandbox/win/src/sandbox_nt_util.cc b/sandbox/win/src/sandbox_nt_util.cc |
index 62f2422ca4324f3e9f6c6fa2140001353c9ca535..dda8e1304e7193182e4010b228813f62f5968a84 100644 |
--- a/sandbox/win/src/sandbox_nt_util.cc |
+++ b/sandbox/win/src/sandbox_nt_util.cc |
@@ -23,58 +23,56 @@ SANDBOX_INTERCEPT NtExports g_nt; |
namespace { |
#if defined(_WIN64) |
+inline char* AlignToBoundary(void* ptr, size_t increment) { |
Will Harris
2016/08/19 16:39:52
can you add some brief function comments on both o
|
+ const size_t kAllocationGranularity = (64 * 1024) - 1; |
+ DWORD_PTR ptr_int = reinterpret_cast<DWORD_PTR>(ptr); |
Will Harris
2016/08/19 16:39:52
can you use uintptr_t here unless you are directly
|
+ DWORD_PTR ret_ptr = |
+ (ptr_int + increment + kAllocationGranularity) & ~kAllocationGranularity; |
+ // Check for overflow. |
+ if (ret_ptr < ptr_int) |
+ return nullptr; |
+ return reinterpret_cast<char*>(ret_ptr); |
+} |
+ |
void* AllocateNearTo(void* source, size_t size) { |
using sandbox::g_nt; |
- |
- // Start with 1 GB above the source. |
- const size_t kOneGB = 0x40000000; |
- void* base = reinterpret_cast<char*>(source) + kOneGB; |
- SIZE_T actual_size = size; |
- ULONG_PTR zero_bits = 0; // Not the correct type if used. |
- ULONG type = MEM_RESERVE; |
- |
- NTSTATUS ret; |
- int attempts = 0; |
- for (; attempts < 41; attempts++) { |
- ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, |
- &actual_size, type, PAGE_READWRITE); |
- if (NT_SUCCESS(ret)) { |
- if (base < source || |
- base >= reinterpret_cast<char*>(source) + 4 * kOneGB) { |
- // We won't be able to patch this dll. |
- VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, |
- MEM_RELEASE)); |
- return NULL; |
- } |
+ // 2GiB max size window. |
+ const size_t kMaxSize = 0x80000000ULL; |
+ // We don't support null as a base. |
+ if (source == nullptr) |
+ return nullptr; |
+ if (size > kMaxSize) |
+ return nullptr; |
+ |
+ char* base = AlignToBoundary(source, 0); |
+ if (base == nullptr) |
+ return nullptr; |
+ // Set top address to be base + 2GiB. If we can't find in this range we're |
+ // stuck. |
+ const char* top_address = base + kMaxSize; |
+ |
+ while (base < top_address) { |
+ MEMORY_BASIC_INFORMATION mem_info; |
+ NTSTATUS status = |
+ g_nt.QueryVirtualMemory(NtCurrentProcess, base, MemoryBasicInformation, |
+ &mem_info, sizeof(mem_info), nullptr); |
+ if (!NT_SUCCESS(status)) |
break; |
- } |
- if (attempts == 30) { |
- // Try the first GB. |
- base = reinterpret_cast<char*>(source); |
- } else if (attempts == 40) { |
- // Try the highest available address. |
- base = NULL; |
- type |= MEM_TOP_DOWN; |
+ if ((mem_info.State == MEM_FREE) && (mem_info.RegionSize >= size)) { |
+ void* ret_base = mem_info.BaseAddress; |
+ status = |
+ g_nt.AllocateVirtualMemory(NtCurrentProcess, &ret_base, 0, &size, |
+ MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); |
+ if (NT_SUCCESS(status)) |
+ return ret_base; |
} |
- // Try 100 MB higher. |
- base = reinterpret_cast<char*>(base) + 100 * 0x100000; |
- } |
- |
- if (attempts == 41) |
- return NULL; |
- |
- ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, zero_bits, |
- &actual_size, MEM_COMMIT, PAGE_READWRITE); |
- |
- if (!NT_SUCCESS(ret)) { |
- VERIFY_SUCCESS(g_nt.FreeVirtualMemory(NtCurrentProcess, &base, &size, |
- MEM_RELEASE)); |
- base = NULL; |
+ base = AlignToBoundary(mem_info.BaseAddress, mem_info.RegionSize); |
+ if (base == nullptr) |
+ break; |
} |
- |
- return base; |
+ return nullptr; |
} |
#else // defined(_WIN64). |
void* AllocateNearTo(void* source, size_t size) { |