Chromium Code Reviews| 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) { |