Bug 1515551 - Add functionality to SharedMemoryBasic to help map the shared memory at an arbitrary address. r=kmag

This patch adds two things:

1. An optional fixed_address argument to SharedMemoryBasic::Map, which
   is the address to map the shared memory at.

2. A FindFreeAddressSpace function that callers can use to find a
   contiguous block of free address space, which can then be used to
   determine an address to pass in to Map that is likely to be free.

Patches in bug 1474793 will use these to place the User Agent style
sheets in a shared memory buffer in the parent process at an address
that is also likely to be free in content processes.

Differential Revision: https://phabricator.services.mozilla.com/D15057

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Cameron McCormack 2019-03-22 00:11:51 +00:00
Родитель f03ec4810c
Коммит bc72d9813e
9 изменённых файлов: 120 добавлений и 23 удалений

Просмотреть файл

@ -67,7 +67,11 @@ class SharedMemory {
// Maps the shared memory into the caller's address space.
// Returns true on success, false otherwise. The memory address
// is accessed via the memory() accessor.
bool Map(size_t bytes);
//
// If the specified fixed address is not null, it is the address that the
// shared memory must be mapped at. Returns false if the shared memory
// could not be mapped at that address.
bool Map(size_t bytes, void* fixed_address = nullptr);
// Unmaps the shared memory from the caller's address space.
// Returns true if successful; returns false on error or if the
@ -94,6 +98,15 @@ class SharedMemory {
// It is safe to call Close repeatedly.
void Close(bool unmap_view = true);
// Returns a page-aligned address at which the given number of bytes could
// probably be mapped. Returns NULL on error or if there is insufficient
// contiguous address space to map the required number of pages.
//
// Note that there is no guarantee that the given address space will actually
// be free by the time this function returns, since another thread might map
// something there in the meantime.
static void* FindFreeAddressSpace(size_t size);
// Share the shared memory to another process. Attempts
// to create a platform-specific new_handle which can be
// used in a remote process to access the shared memory

Просмотреть файл

@ -156,16 +156,30 @@ bool SharedMemory::Create(size_t size) {
return true;
}
bool SharedMemory::Map(size_t bytes) {
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
if (mapped_file_ == -1) return false;
memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
MAP_SHARED, mapped_file_, 0);
if (memory_) max_size_ = bytes;
// Don't use MAP_FIXED when a fixed_address was specified, since that can
// replace pages that are alread mapped at that address.
memory_ =
mmap(fixed_address, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
MAP_SHARED, mapped_file_, 0);
bool mmap_succeeded = (memory_ != (void*)-1);
DCHECK(mmap_succeeded) << "Call to mmap failed, errno=" << errno;
if (mmap_succeeded) {
if (fixed_address && memory_ != fixed_address) {
bool munmap_succeeded = munmap(memory_, bytes) == 0;
DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
memory_ = NULL;
return false;
}
max_size_ = bytes;
}
return mmap_succeeded;
}
@ -178,6 +192,13 @@ bool SharedMemory::Unmap() {
return true;
}
void* SharedMemory::FindFreeAddressSpace(size_t size) {
void* memory =
mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
munmap(memory, size);
return memory != MAP_FAILED ? memory : NULL;
}
bool SharedMemory::ShareToProcessCommon(ProcessId processId,
SharedMemoryHandle* new_handle,
bool close_self) {

Просмотреть файл

@ -109,17 +109,19 @@ bool SharedMemory::Create(size_t size) {
return true;
}
bool SharedMemory::Map(size_t bytes) {
bool SharedMemory::Map(size_t bytes, void* fixed_address) {
if (mapped_file_ == NULL) return false;
if (external_section_ && !IsSectionSafeToMap(mapped_file_)) {
return false;
}
memory_ = MapViewOfFile(
memory_ = MapViewOfFileEx(
mapped_file_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
0, 0, bytes);
0, 0, bytes, fixed_address);
if (memory_ != NULL) {
MOZ_ASSERT(!fixed_address || memory_ == fixed_address,
"MapViewOfFileEx returned an expected address");
return true;
}
return false;
@ -133,6 +135,14 @@ bool SharedMemory::Unmap() {
return true;
}
void* SharedMemory::FindFreeAddressSpace(size_t size) {
void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
if (memory) {
VirtualFree(memory, 0, MEM_RELEASE);
}
return memory;
}
bool SharedMemory::ShareToProcessCommon(ProcessId processId,
SharedMemoryHandle* new_handle,
bool close_self) {

Просмотреть файл

@ -50,7 +50,7 @@ class SharedMemory {
virtual void* memory() const = 0;
virtual bool Create(size_t size) = 0;
virtual bool Map(size_t nBytes) = 0;
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) = 0;
virtual void CloseHandle() = 0;

Просмотреть файл

@ -68,7 +68,7 @@ bool SharedMemoryBasic::Create(size_t aNbytes) {
return true;
}
bool SharedMemoryBasic::Map(size_t nBytes) {
bool SharedMemoryBasic::Map(size_t nBytes, void* fixed_address) {
MOZ_ASSERT(nullptr == mMemory, "Already Map()d");
int prot = PROT_READ;
@ -76,17 +76,37 @@ bool SharedMemoryBasic::Map(size_t nBytes) {
prot |= PROT_WRITE;
}
mMemory = mmap(nullptr, nBytes, prot, MAP_SHARED, mShmFd, 0);
// Don't use MAP_FIXED when a fixed_address was specified, since that can
// replace pages that are alread mapped at that address.
mMemory = mmap(fixed_address, nBytes, prot, MAP_SHARED, mShmFd, 0);
if (MAP_FAILED == mMemory) {
LogError("ShmemAndroid::Map()");
if (!fixed_address) {
LogError("ShmemAndroid::Map()");
}
mMemory = nullptr;
return false;
}
if (fixed_address && mMemory != fixed_address) {
if (munmap(mMemory, nBytes)) {
LogError("ShmemAndroid::Map():unmap");
mMemory = nullptr;
return false;
}
}
Mapped(nBytes);
return true;
}
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
void* memory =
mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
munmap(memory, size);
return memory != (void*)-1 ? memory : NULL;
}
bool SharedMemoryBasic::ShareToProcess(base::ProcessId /*unused*/,
Handle* aNewHandle) {
MOZ_ASSERT(mShmFd >= 0, "Should have been Create()d by now");

Просмотреть файл

@ -32,7 +32,7 @@ class SharedMemoryBasic final
virtual bool Create(size_t aNbytes) override;
virtual bool Map(size_t nBytes) override;
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override;
virtual void CloseHandle() override;
@ -48,6 +48,8 @@ class SharedMemoryBasic final
static Handle NULLHandle() { return Handle(); }
static void* FindFreeAddressSpace(size_t aSize);
virtual bool IsHandleValid(const Handle& aHandle) const override {
return aHandle.fd >= 0;
}

Просмотреть файл

@ -41,8 +41,8 @@ class SharedMemoryBasic final
return ok;
}
virtual bool Map(size_t nBytes) override {
bool ok = mSharedMemory.Map(nBytes);
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override {
bool ok = mSharedMemory.Map(nBytes, fixed_address);
if (ok) {
Mapped(nBytes);
}
@ -76,6 +76,10 @@ class SharedMemoryBasic final
return ret;
}
static void* FindFreeAddressSpace(size_t size) {
return base::SharedMemory::FindFreeAddressSpace(size);
}
private:
~SharedMemoryBasic() {}

Просмотреть файл

@ -70,7 +70,7 @@ class SharedMemoryBasic final : public SharedMemoryCommon<mach_port_t> {
virtual bool Create(size_t aNbytes) override;
virtual bool Map(size_t nBytes) override;
virtual bool Map(size_t nBytes, void* fixed_address = nullptr) override;
virtual void CloseHandle() override;
@ -86,6 +86,8 @@ class SharedMemoryBasic final : public SharedMemoryCommon<mach_port_t> {
static Handle NULLHandle() { return Handle(); }
static void* FindFreeAddressSpace(size_t aSize);
virtual bool IsHandleValid(const Handle& aHandle) const override;
virtual bool ShareToProcess(base::ProcessId aProcessId,

Просмотреть файл

@ -512,7 +512,7 @@ bool SharedMemoryBasic::Create(size_t size) {
return true;
}
bool SharedMemoryBasic::Map(size_t size) {
bool SharedMemoryBasic::Map(size_t size, void* fixed_address) {
MOZ_ASSERT(mMemory == nullptr);
if (MACH_PORT_NULL == mPort) {
@ -520,18 +520,31 @@ bool SharedMemoryBasic::Map(size_t size) {
}
kern_return_t kr;
mach_vm_address_t address = 0;
mach_vm_address_t address = toVMAddress(fixed_address);
vm_prot_t vmProtection = VM_PROT_READ;
if (mOpenRights == RightsReadWrite) {
vmProtection |= VM_PROT_WRITE;
}
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, VM_FLAGS_ANYWHERE, mPort, 0,
false, vmProtection, vmProtection, VM_INHERIT_NONE);
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0,
fixed_address ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
mPort, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n", size,
mach_task_self(), mPort, mach_error_string(kr), kr);
if (!fixed_address) {
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
size, mach_task_self(), mPort, mach_error_string(kr), kr);
}
return false;
}
if (fixed_address && fixed_address != toPointer(address)) {
kr = vm_deallocate(mach_task_self(), address, size);
if (kr != KERN_SUCCESS) {
LOG_ERROR("Failed to unmap shared memory at unsuitable address "
"(%zu bytes) from %x, port %x. %s (%x)\n",
size, mach_task_self(), mPort, mach_error_string(kr), kr);
}
return false;
}
@ -540,6 +553,18 @@ bool SharedMemoryBasic::Map(size_t size) {
return true;
}
void* SharedMemoryBasic::FindFreeAddressSpace(size_t size) {
mach_vm_address_t address = 0;
size = round_page(size);
if (mach_vm_map(mach_task_self(), &address, size, 0,
VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE,
VM_PROT_NONE, VM_INHERIT_NONE) != KERN_SUCCESS ||
vm_deallocate(mach_task_self(), address, size) != KERN_SUCCESS) {
return nullptr;
}
return toPointer(address);
}
bool SharedMemoryBasic::ShareToProcess(base::ProcessId pid, Handle* aNewHandle) {
if (pid == getpid()) {
*aNewHandle = mPort;