Commit 24d17720 authored by Bill Budge's avatar Bill Budge Committed by Commit Bot

[page_allocator] Adjust address space when allocating guarded memory.

- Linux limits address space. On 64 bit systems, we may allocate
  multiple guarded memory regions which exceed this limit. Attempt to
  raise the limit when making large reservations.
- Lower the limit when releasing large guarded allocations.

Bug: chromium:799573
Change-Id: Ied5694b541780914fc05c5e4f0f9a1338a2901e4
Reviewed-on: https://chromium-review.googlesource.com/922913
Commit-Queue: Bill Budge <bbudge@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537385}
parent 59b1aac2
...@@ -10,21 +10,25 @@ ...@@ -10,21 +10,25 @@
#include "base/allocator/partition_allocator/address_space_randomization.h" #include "base/allocator/partition_allocator/address_space_randomization.h"
#include "base/allocator/partition_allocator/spin_lock.h" #include "base/allocator/partition_allocator/spin_lock.h"
#include "base/compiler_specific.h"
#include "base/base_export.h" #include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/numerics/checked_math.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(OS_MACOSX)
#include <mach/mach.h>
#endif
#if defined(OS_POSIX) #if defined(OS_POSIX)
#include <errno.h> #include <errno.h>
#include <sys/mman.h> #include <sys/mman.h>
#if defined(OS_MACOSX)
#include <mach/mach.h>
#endif
#if defined(OS_LINUX)
#include <sys/resource.h>
#endif
#ifndef MADV_FREE #ifndef MADV_FREE
#define MADV_FREE MADV_DONTNEED #define MADV_FREE MADV_DONTNEED
#endif #endif
...@@ -57,6 +61,27 @@ int GetAccessFlags(PageAccessibilityConfiguration page_accessibility) { ...@@ -57,6 +61,27 @@ int GetAccessFlags(PageAccessibilityConfiguration page_accessibility) {
} }
} }
#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
// On Linux, multiple guarded memory regions may exceed the process address
// space limit. This function will raise or lower the limit by |amount|.
bool AdjustAddressSpaceLimit(int64_t amount) {
struct rlimit old_rlimit;
if (getrlimit(RLIMIT_AS, &old_rlimit))
return false;
const rlim_t new_limit =
CheckAdd(old_rlimit.rlim_cur, amount).ValueOrDefault(old_rlimit.rlim_max);
const struct rlimit new_rlimit = {std::min(new_limit, old_rlimit.rlim_max),
old_rlimit.rlim_max};
// setrlimit will fail if limit > old_rlimit.rlim_max.
return setrlimit(RLIMIT_AS, &new_rlimit) == 0;
}
// Current WASM guarded memory regions have 8 GiB of address space. There are
// schemes that reduce that to 4 GiB.
constexpr size_t kMinimumGuardedMemorySize = 1ULL << 32; // 4 GiB
#endif // defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
#elif defined(OS_WIN) #elif defined(OS_WIN)
#include <windows.h> #include <windows.h>
...@@ -220,6 +245,19 @@ void* AllocPages(void* address, ...@@ -220,6 +245,19 @@ void* AllocPages(void* address,
uintptr_t align_base_mask = ~align_offset_mask; uintptr_t align_base_mask = ~align_offset_mask;
DCHECK(!(reinterpret_cast<uintptr_t>(address) & align_offset_mask)); DCHECK(!(reinterpret_cast<uintptr_t>(address) & align_offset_mask));
#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
// On 64 bit Linux, we may need to adjust the address space limit for
// guarded allocations.
if (length >= kMinimumGuardedMemorySize) {
CHECK_EQ(PageInaccessible, page_accessibility);
CHECK(!commit);
if (AdjustAddressSpaceLimit(base::checked_cast<int64_t>(length))) {
DLOG(WARNING) << "Could not address space by " << length;
// Fall through. Try the allocation, since we may have a reserve.
}
}
#endif
// If the client passed null as the address, choose a good one. // If the client passed null as the address, choose a good one.
if (address == nullptr) { if (address == nullptr) {
address = GetRandomPageBase(); address = GetRandomPageBase();
...@@ -291,6 +329,12 @@ void FreePages(void* address, size_t length) { ...@@ -291,6 +329,12 @@ void FreePages(void* address, size_t length) {
#if defined(OS_POSIX) #if defined(OS_POSIX)
int ret = munmap(address, length); int ret = munmap(address, length);
CHECK(!ret); CHECK(!ret);
#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
// On 64 bit Linux, restore the address space limit.
if (length >= kMinimumGuardedMemorySize) {
CHECK(AdjustAddressSpaceLimit(-base::checked_cast<int64_t>(length)));
}
#endif
#else #else
BOOL ret = VirtualFree(address, 0, MEM_RELEASE); BOOL ret = VirtualFree(address, 0, MEM_RELEASE);
CHECK(ret); CHECK(ret);
......
...@@ -340,7 +340,7 @@ TEST(PageAllocatorTest, AllocFailure) { ...@@ -340,7 +340,7 @@ TEST(PageAllocatorTest, AllocFailure) {
return; return;
void* result = base::AllocPages(nullptr, size, kPageAllocationGranularity, void* result = base::AllocPages(nullptr, size, kPageAllocationGranularity,
PageInaccessible); PageInaccessible, PageTag::kChromium, false);
if (result == nullptr) { if (result == nullptr) {
// We triggered allocation failure. Our reservation should have been // We triggered allocation failure. Our reservation should have been
// released, and we should be able to make a new reservation. // released, and we should be able to make a new reservation.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment