1d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov/*
2d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * Copyright (C) 2013 The Android Open Source Project
3d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov *
4d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * Licensed under the Apache License, Version 2.0 (the "License");
5d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * you may not use this file except in compliance with the License.
6d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * You may obtain a copy of the License at
7d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov *
8d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov *      http://www.apache.org/licenses/LICENSE-2.0
9d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov *
10d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * Unless required by applicable law or agreed to in writing, software
11d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * distributed under the License is distributed on an "AS IS" BASIS,
12d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * See the License for the specific language governing permissions and
14d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * limitations under the License.
15d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov */
16d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
17d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include <stdlib.h>
18d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include <string.h>
19d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include <sys/mman.h>
20d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
21d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include <gtest/gtest.h>
22d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
23d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include "../linker_allocator.h"
24d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
25d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov#include <unistd.h>
26d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
27d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovnamespace {
28d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
29d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovstruct test_struct_nominal {
30d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  void* pointer;
31d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ssize_t value;
32d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov};
33d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
34d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov/*
35d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * this one has size below allocator cap which is 2*sizeof(void*)
36d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov */
37d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovstruct test_struct_small {
38d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  char dummy_str[5];
39d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov};
40d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
41d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov/*
42d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov * 1009 byte struct (1009 is prime)
43d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov */
44d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovstruct test_struct_larger {
45d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  char dummy_str[1009];
46d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov};
47d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
48d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovstatic size_t kPageSize = sysconf(_SC_PAGE_SIZE);
49d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov};
50d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
51d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy IvanovTEST(linker_allocator, test_nominal) {
52d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  LinkerAllocator<test_struct_nominal> allocator;
53d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
54d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_nominal* ptr1 = allocator.alloc();
55d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr1 != nullptr);
56d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_nominal* ptr2 = allocator.alloc();
57d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr2 != nullptr);
58d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  // they should be next to each other.
59d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_EQ(ptr1+1, ptr2);
60d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
61d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ptr1->value = 42;
62d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
63d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  allocator.free(ptr1);
64d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  allocator.free(ptr2);
65d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov}
66d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
67d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy IvanovTEST(linker_allocator, test_small) {
68d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  LinkerAllocator<test_struct_small> allocator;
69d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
70d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  char* ptr1 = reinterpret_cast<char*>(allocator.alloc());
71d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  char* ptr2 = reinterpret_cast<char*>(allocator.alloc());
72d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
73d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr1 != nullptr);
74d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr2 != nullptr);
75d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_EQ(ptr1+2*sizeof(void*), ptr2);
76d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov}
77d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
78d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy IvanovTEST(linker_allocator, test_larger) {
79d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  LinkerAllocator<test_struct_larger> allocator;
80d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
81d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_larger* ptr1 = allocator.alloc();
82d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_larger* ptr2 = allocator.alloc();
83d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
84d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr1 != nullptr);
85d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_TRUE(ptr2 != nullptr);
86d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
87d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_EQ(ptr1+1, ptr2);
88d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
89d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  // lets allocate until we reach next page.
90d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  size_t n = kPageSize/sizeof(test_struct_larger) + 1 - 2;
91d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
92d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  for (size_t i=0; i<n; ++i) {
93d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov    ASSERT_TRUE(allocator.alloc() != nullptr);
94d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  }
95d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
961079406cab09090cc11e26d4ac2f1ba9c4930cdbDmitriy Ivanov  test_struct_larger* ptr_to_free = allocator.alloc();
971079406cab09090cc11e26d4ac2f1ba9c4930cdbDmitriy Ivanov  ASSERT_TRUE(ptr_to_free != nullptr);
981079406cab09090cc11e26d4ac2f1ba9c4930cdbDmitriy Ivanov  allocator.free(ptr1);
99d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov}
100d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
101d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanovstatic void protect_all() {
102d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  LinkerAllocator<test_struct_larger> allocator;
103d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
104d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  // number of allocs to reach the end of first page
105d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  size_t n = kPageSize/sizeof(test_struct_larger) - 1;
106d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_larger* page1_ptr = allocator.alloc();
107d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
108d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  for (size_t i=0; i<n; ++i) {
109d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov    allocator.alloc();
110d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  }
111d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
112d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  test_struct_larger* page2_ptr = allocator.alloc();
113d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  allocator.protect_all(PROT_READ);
114d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  allocator.protect_all(PROT_READ | PROT_WRITE);
115d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  // check access
116d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  page2_ptr->dummy_str[23] = 27;
117d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  page1_ptr->dummy_str[13] = 11;
118d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
119d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  allocator.protect_all(PROT_READ);
120d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  fprintf(stderr, "trying to access protected page");
121d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
122d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  // this should result in segmentation fault
123d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  page1_ptr->dummy_str[11] = 7;
124d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov}
125d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
126d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy IvanovTEST(linker_allocator, test_protect) {
127d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  testing::FLAGS_gtest_death_test_style = "threadsafe";
128d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov  ASSERT_EXIT(protect_all(), testing::KilledBySignal(SIGSEGV), "trying to access protected page");
129d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov}
130d597d263bc32422402d4810ce4ec070f0227c2f7Dmitriy Ivanov
131