Merge "Refactor linker allocator"
This commit is contained in:
commit
d44927b8e9
@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \
|
||||
debugger.cpp \
|
||||
dlfcn.cpp \
|
||||
linker.cpp \
|
||||
linker_allocator.cpp \
|
||||
linker_environ.cpp \
|
||||
linker_phdr.cpp \
|
||||
rt.cpp \
|
||||
@ -67,3 +68,5 @@ LOCAL_INSTALLED_MODULE_STEM :=
|
||||
LOCAL_INTERMEDIATE_TARGETS :=
|
||||
include $(LOCAL_PATH)/linker_executable.mk
|
||||
endif
|
||||
|
||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||
|
79
linker/linker.cpp
Executable file → Normal file
79
linker/linker.cpp
Executable file → Normal file
@ -48,6 +48,7 @@
|
||||
#include "linker_debug.h"
|
||||
#include "linker_environ.h"
|
||||
#include "linker_phdr.h"
|
||||
#include "linker_allocator.h"
|
||||
|
||||
/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
|
||||
*
|
||||
@ -69,14 +70,8 @@ static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf);
|
||||
|
||||
// We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
|
||||
// maps, each a single page in size. The pages are broken up into as many struct soinfo
|
||||
// objects as will fit, and they're all threaded together on a free list.
|
||||
#define SOINFO_PER_POOL ((PAGE_SIZE - sizeof(soinfo_pool_t*)) / sizeof(soinfo))
|
||||
struct soinfo_pool_t {
|
||||
soinfo_pool_t* next;
|
||||
soinfo info[SOINFO_PER_POOL];
|
||||
};
|
||||
static struct soinfo_pool_t* gSoInfoPools = NULL;
|
||||
static soinfo* gSoInfoFreeList = NULL;
|
||||
// objects as will fit.
|
||||
static LinkerAllocator<soinfo> gSoInfoAllocator;
|
||||
|
||||
static soinfo* solist = &libdl_info;
|
||||
static soinfo* sonext = &libdl_info;
|
||||
@ -269,56 +264,13 @@ void notify_gdb_of_libraries() {
|
||||
rtld_db_dlactivity();
|
||||
}
|
||||
|
||||
static bool ensure_free_list_non_empty() {
|
||||
if (gSoInfoFreeList != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate a new pool.
|
||||
soinfo_pool_t* pool = reinterpret_cast<soinfo_pool_t*>(mmap(NULL, sizeof(*pool),
|
||||
PROT_READ|PROT_WRITE,
|
||||
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0));
|
||||
if (pool == MAP_FAILED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add the pool to our list of pools.
|
||||
pool->next = gSoInfoPools;
|
||||
gSoInfoPools = pool;
|
||||
|
||||
// Chain the entries in the new pool onto the free list.
|
||||
gSoInfoFreeList = &pool->info[0];
|
||||
soinfo* next = NULL;
|
||||
for (int i = SOINFO_PER_POOL - 1; i >= 0; --i) {
|
||||
pool->info[i].next = next;
|
||||
next = &pool->info[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_soinfo_pool_protection(int protection) {
|
||||
for (soinfo_pool_t* p = gSoInfoPools; p != NULL; p = p->next) {
|
||||
if (mprotect(p, sizeof(*p), protection) == -1) {
|
||||
abort(); // Can't happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static soinfo* soinfo_alloc(const char* name) {
|
||||
if (strlen(name) >= SOINFO_NAME_LEN) {
|
||||
DL_ERR("library name \"%s\" too long", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ensure_free_list_non_empty()) {
|
||||
DL_ERR("out of memory when loading \"%s\"", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Take the head element off the free list.
|
||||
soinfo* si = gSoInfoFreeList;
|
||||
gSoInfoFreeList = gSoInfoFreeList->next;
|
||||
soinfo* si = gSoInfoAllocator.alloc();
|
||||
|
||||
// Initialize the new element.
|
||||
memset(si, 0, sizeof(soinfo));
|
||||
@ -357,8 +309,8 @@ static void soinfo_free(soinfo* si) {
|
||||
if (si == sonext) {
|
||||
sonext = prev;
|
||||
}
|
||||
si->next = gSoInfoFreeList;
|
||||
gSoInfoFreeList = si;
|
||||
|
||||
gSoInfoAllocator.free(si);
|
||||
}
|
||||
|
||||
|
||||
@ -794,8 +746,8 @@ static int soinfo_unload(soinfo* si) {
|
||||
|
||||
munmap(reinterpret_cast<void*>(si->base), si->size);
|
||||
notify_gdb_of_unload(si);
|
||||
soinfo_free(si);
|
||||
si->ref_count = 0;
|
||||
soinfo_free(si);
|
||||
} else {
|
||||
si->ref_count--;
|
||||
TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count);
|
||||
@ -822,19 +774,19 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo)
|
||||
DL_ERR("invalid extended flags to android_dlopen_ext: %x", extinfo->flags);
|
||||
return NULL;
|
||||
}
|
||||
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||
gSoInfoAllocator.protect_all(PROT_READ | PROT_WRITE);
|
||||
soinfo* si = find_library(name, extinfo);
|
||||
if (si != NULL) {
|
||||
si->CallConstructors();
|
||||
}
|
||||
set_soinfo_pool_protection(PROT_READ);
|
||||
gSoInfoAllocator.protect_all(PROT_READ);
|
||||
return si;
|
||||
}
|
||||
|
||||
int do_dlclose(soinfo* si) {
|
||||
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||
gSoInfoAllocator.protect_all(PROT_READ | PROT_WRITE);
|
||||
int result = soinfo_unload(si);
|
||||
set_soinfo_pool_protection(PROT_READ);
|
||||
gSoInfoAllocator.protect_all(PROT_READ);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1382,7 +1334,7 @@ void soinfo::CallFunction(const char* function_name __unused, linker_function_t
|
||||
|
||||
// The function may have called dlopen(3) or dlclose(3), so we need to ensure our data structures
|
||||
// are still writable. This happens with our debug malloc (see http://b/7941716).
|
||||
set_soinfo_pool_protection(PROT_READ | PROT_WRITE);
|
||||
gSoInfoAllocator.protect_all(PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
void soinfo::CallPreInitConstructors() {
|
||||
@ -1933,6 +1885,11 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
|
||||
ldpreload_env = linker_env_get("LD_PRELOAD");
|
||||
}
|
||||
|
||||
// Linker does not call constructors for its own
|
||||
// global variables so we need to initialize
|
||||
// the allocator explicitly.
|
||||
gSoInfoAllocator.init();
|
||||
|
||||
INFO("[ android linker & debugger ]");
|
||||
|
||||
soinfo* si = soinfo_alloc(args.argv[0]);
|
||||
@ -2150,7 +2107,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||
args.abort_message_ptr = &gAbortMessage;
|
||||
ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);
|
||||
|
||||
set_soinfo_pool_protection(PROT_READ);
|
||||
gSoInfoAllocator.protect_all(PROT_READ);
|
||||
|
||||
// Return the address that the calling assembly stub should jump to.
|
||||
return start_address;
|
||||
|
142
linker/linker_allocator.cpp
Normal file
142
linker/linker_allocator.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "linker_allocator.h"
|
||||
#include <inttypes.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct LinkerAllocatorPage {
|
||||
LinkerAllocatorPage* next;
|
||||
uint8_t bytes[PAGE_SIZE-sizeof(LinkerAllocatorPage*)];
|
||||
};
|
||||
|
||||
struct FreeBlockInfo {
|
||||
void* next_block;
|
||||
size_t num_free_blocks;
|
||||
};
|
||||
|
||||
LinkerBlockAllocator::LinkerBlockAllocator()
|
||||
: block_size_(0),
|
||||
page_list_(nullptr),
|
||||
free_block_list_(nullptr)
|
||||
{}
|
||||
|
||||
void LinkerBlockAllocator::init(size_t block_size) {
|
||||
block_size_ = block_size < sizeof(FreeBlockInfo) ? sizeof(FreeBlockInfo) : block_size;
|
||||
}
|
||||
|
||||
|
||||
void* LinkerBlockAllocator::alloc() {
|
||||
if (free_block_list_ == nullptr) {
|
||||
create_new_page();
|
||||
} else {
|
||||
protect_page(free_block_list_, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
|
||||
FreeBlockInfo* block_info = reinterpret_cast<FreeBlockInfo*>(free_block_list_);
|
||||
if (block_info->num_free_blocks > 1) {
|
||||
FreeBlockInfo* next_block_info = reinterpret_cast<FreeBlockInfo*>(
|
||||
reinterpret_cast<char*>(free_block_list_) + block_size_);
|
||||
next_block_info->next_block = block_info->next_block;
|
||||
next_block_info->num_free_blocks = block_info->num_free_blocks - 1;
|
||||
free_block_list_ = next_block_info;
|
||||
} else {
|
||||
free_block_list_ = block_info->next_block;
|
||||
}
|
||||
|
||||
block_info->next_block = nullptr;
|
||||
block_info->num_free_blocks = 0;
|
||||
|
||||
return block_info;
|
||||
}
|
||||
|
||||
void LinkerBlockAllocator::free(void* block) {
|
||||
if (block == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
LinkerAllocatorPage* page = find_page(block);
|
||||
|
||||
if (page == nullptr) {
|
||||
abort();
|
||||
}
|
||||
|
||||
ssize_t offset = reinterpret_cast<uint8_t*>(block) - page->bytes;
|
||||
|
||||
if (offset % block_size_ != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
FreeBlockInfo* block_info = reinterpret_cast<FreeBlockInfo*>(block);
|
||||
|
||||
protect_page(block_info, PROT_READ | PROT_WRITE);
|
||||
block_info->next_block = free_block_list_;
|
||||
block_info->num_free_blocks = 1;
|
||||
protect_page(block_info, PROT_READ);
|
||||
|
||||
free_block_list_ = block_info;
|
||||
}
|
||||
|
||||
void LinkerBlockAllocator::protect_all(int prot) {
|
||||
for (LinkerAllocatorPage* page = page_list_; page != nullptr; page = page->next) {
|
||||
if (mprotect(page, PAGE_SIZE, prot) == -1) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinkerBlockAllocator::protect_page(void* block, int prot) {
|
||||
LinkerAllocatorPage* page = find_page(block);
|
||||
if (page == nullptr || mprotect(page, PAGE_SIZE, prot) == -1) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LinkerBlockAllocator::create_new_page() {
|
||||
LinkerAllocatorPage* page = reinterpret_cast<LinkerAllocatorPage*>(mmap(nullptr, PAGE_SIZE,
|
||||
PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0));
|
||||
if (page == MAP_FAILED) {
|
||||
abort(); // oom
|
||||
}
|
||||
|
||||
FreeBlockInfo* first_block = reinterpret_cast<FreeBlockInfo*>(page->bytes);
|
||||
first_block->next_block = free_block_list_;
|
||||
first_block->num_free_blocks = (PAGE_SIZE - sizeof(LinkerAllocatorPage*))/block_size_;
|
||||
|
||||
free_block_list_ = first_block;
|
||||
|
||||
page->next = page_list_;
|
||||
page_list_ = page;
|
||||
}
|
||||
|
||||
LinkerAllocatorPage* LinkerBlockAllocator::find_page(void* block) {
|
||||
if (block == nullptr) {
|
||||
abort();
|
||||
}
|
||||
|
||||
LinkerAllocatorPage* page = page_list_;
|
||||
const uint8_t* page_ptr = reinterpret_cast<const uint8_t*>(page);
|
||||
while (page != nullptr) {
|
||||
if (block >= (page_ptr + sizeof(page->next)) && block < (page_ptr + PAGE_SIZE)) {
|
||||
return page;
|
||||
}
|
||||
|
||||
page = page->next;
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
72
linker/linker_allocator.h
Normal file
72
linker/linker_allocator.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __LINKER_ALLOCATOR_H
|
||||
#define __LINKER_ALLOCATOR_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include "private/bionic_macros.h"
|
||||
|
||||
struct LinkerAllocatorPage;
|
||||
|
||||
/*
|
||||
* This class is a non-template version of the LinkerAllocator
|
||||
* It keeps code inside .cpp file by keeping the interface
|
||||
* template-free.
|
||||
*
|
||||
* Please use LinkerAllocator<type> where possible (everywhere).
|
||||
*/
|
||||
class LinkerBlockAllocator {
|
||||
public:
|
||||
LinkerBlockAllocator();
|
||||
|
||||
void init(size_t block_size);
|
||||
void* alloc();
|
||||
void free(void* block);
|
||||
void protect_page(void* block, int prot);
|
||||
void protect_all(int prot);
|
||||
|
||||
private:
|
||||
void create_new_page();
|
||||
LinkerAllocatorPage* find_page(void* block);
|
||||
|
||||
size_t block_size_;
|
||||
LinkerAllocatorPage* page_list_;
|
||||
void* free_block_list_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(LinkerBlockAllocator);
|
||||
};
|
||||
|
||||
/*
|
||||
* A simple allocator for the dynamic linker. An allocator allocates instances
|
||||
* of a single fixed-size type. Allocations are backed by page-sized private
|
||||
* anonymous mmaps.
|
||||
*/
|
||||
template<typename T>
|
||||
class LinkerAllocator {
|
||||
public:
|
||||
LinkerAllocator() : block_allocator_() {}
|
||||
void init() { block_allocator_.init(sizeof(T)); }
|
||||
T* alloc() { return reinterpret_cast<T*>(block_allocator_.alloc()); }
|
||||
void free(T* t) { block_allocator_.free(t); }
|
||||
void protect_page(T* t, int prot) { block_allocator_.protect_page(t, prot); }
|
||||
void protect_all(int prot) { block_allocator_.protect_all(prot); }
|
||||
private:
|
||||
LinkerBlockAllocator block_allocator_;
|
||||
DISALLOW_COPY_AND_ASSIGN(LinkerAllocator);
|
||||
};
|
||||
#endif // __LINKER_ALLOCATOR_H
|
38
linker/tests/Android.mk
Normal file
38
linker/tests/Android.mk
Normal file
@ -0,0 +1,38 @@
|
||||
#
|
||||
# Copyright (C) 2012 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
ifneq ($(BUILD_TINY_ANDROID),true)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MULTILIB := both
|
||||
LOCAL_MODULE := linker-unit-tests
|
||||
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
|
||||
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
|
||||
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
|
||||
|
||||
LOCAL_CFLAGS += -g -Wall -Wextra -Werror -std=gnu++11
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../libc/
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
linker_allocator_test.cpp \
|
||||
../linker_allocator.cpp
|
||||
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
endif # !BUILD_TINY_ANDROID
|
161
linker/tests/linker_allocator_test.cpp
Normal file
161
linker/tests/linker_allocator_test.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "../linker_allocator.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct test_struct_nominal {
|
||||
void* pointer;
|
||||
ssize_t value;
|
||||
};
|
||||
|
||||
/*
|
||||
* this one has size below allocator cap which is 2*sizeof(void*)
|
||||
*/
|
||||
struct test_struct_small {
|
||||
char dummy_str[5];
|
||||
};
|
||||
|
||||
/*
|
||||
* 1009 byte struct (1009 is prime)
|
||||
*/
|
||||
struct test_struct_larger {
|
||||
char dummy_str[1009];
|
||||
};
|
||||
|
||||
static size_t kPageSize = sysconf(_SC_PAGE_SIZE);
|
||||
};
|
||||
|
||||
TEST(linker_allocator, test_nominal) {
|
||||
LinkerAllocator<test_struct_nominal> allocator;
|
||||
allocator.init();
|
||||
|
||||
test_struct_nominal* ptr1 = allocator.alloc();
|
||||
ASSERT_TRUE(ptr1 != nullptr);
|
||||
test_struct_nominal* ptr2 = allocator.alloc();
|
||||
ASSERT_TRUE(ptr2 != nullptr);
|
||||
// they should be next to each other.
|
||||
ASSERT_EQ(ptr1+1, ptr2);
|
||||
|
||||
ptr1->value = 42;
|
||||
|
||||
allocator.protect_page(ptr1, PROT_READ);
|
||||
|
||||
allocator.free(ptr1);
|
||||
allocator.free(ptr2);
|
||||
}
|
||||
|
||||
TEST(linker_allocator, test_small) {
|
||||
LinkerAllocator<test_struct_small> allocator;
|
||||
allocator.init();
|
||||
|
||||
char* ptr1 = reinterpret_cast<char*>(allocator.alloc());
|
||||
char* ptr2 = reinterpret_cast<char*>(allocator.alloc());
|
||||
|
||||
ASSERT_TRUE(ptr1 != nullptr);
|
||||
ASSERT_TRUE(ptr2 != nullptr);
|
||||
ASSERT_EQ(ptr1+2*sizeof(void*), ptr2);
|
||||
}
|
||||
|
||||
TEST(linker_allocator, test_larger) {
|
||||
LinkerAllocator<test_struct_larger> allocator;
|
||||
allocator.init();
|
||||
|
||||
test_struct_larger* ptr1 = allocator.alloc();
|
||||
test_struct_larger* ptr2 = allocator.alloc();
|
||||
|
||||
ASSERT_TRUE(ptr1 != nullptr);
|
||||
ASSERT_TRUE(ptr2 != nullptr);
|
||||
|
||||
ASSERT_EQ(ptr1+1, ptr2);
|
||||
|
||||
allocator.protect_page(ptr2, PROT_READ);
|
||||
|
||||
// lets allocate until we reach next page.
|
||||
size_t n = kPageSize/sizeof(test_struct_larger) + 1 - 2;
|
||||
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
ASSERT_TRUE(allocator.alloc() != nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void protect_one_page() {
|
||||
LinkerAllocator<test_struct_larger> allocator;
|
||||
allocator.init();
|
||||
|
||||
// number of allocs to reach the end of first page
|
||||
size_t n = kPageSize/sizeof(test_struct_larger) - 1;
|
||||
test_struct_larger* page1_ptr = allocator.alloc();
|
||||
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
allocator.alloc();
|
||||
}
|
||||
|
||||
test_struct_larger* page2_ptr = allocator.alloc();
|
||||
|
||||
allocator.protect_page(page2_ptr, PROT_READ);
|
||||
|
||||
// check that we still have access to page1
|
||||
page1_ptr->dummy_str[17] = 52;
|
||||
|
||||
fprintf(stderr, "trying to access protected page");
|
||||
|
||||
// this should result in segmentation fault
|
||||
page2_ptr->dummy_str[12] = 3;
|
||||
}
|
||||
|
||||
static void protect_all() {
|
||||
LinkerAllocator<test_struct_larger> allocator;
|
||||
allocator.init();
|
||||
|
||||
// number of allocs to reach the end of first page
|
||||
size_t n = kPageSize/sizeof(test_struct_larger) - 1;
|
||||
test_struct_larger* page1_ptr = allocator.alloc();
|
||||
|
||||
for (size_t i=0; i<n; ++i) {
|
||||
allocator.alloc();
|
||||
}
|
||||
|
||||
test_struct_larger* page2_ptr = allocator.alloc();
|
||||
allocator.protect_all(PROT_READ);
|
||||
allocator.protect_all(PROT_READ | PROT_WRITE);
|
||||
// check access
|
||||
page2_ptr->dummy_str[23] = 27;
|
||||
page1_ptr->dummy_str[13] = 11;
|
||||
|
||||
allocator.protect_all(PROT_READ);
|
||||
fprintf(stderr, "trying to access protected page");
|
||||
|
||||
// this should result in segmentation fault
|
||||
page1_ptr->dummy_str[11] = 7;
|
||||
}
|
||||
|
||||
TEST(linker_allocator, test_protect) {
|
||||
testing::FLAGS_gtest_death_test_style = "threadsafe";
|
||||
ASSERT_EXIT(protect_one_page(), testing::KilledBySignal(SIGSEGV), "trying to access protected page");
|
||||
ASSERT_EXIT(protect_all(), testing::KilledBySignal(SIGSEGV), "trying to access protected page");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user