1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdint.h>
18
19 #include <thread>
20 #include <vector>
21
22 #include <gtest/gtest.h>
23
24 #include "MemoryCache.h"
25 #include "utils/MemoryFake.h"
26
27 namespace unwindstack {
28
29 class MemoryThreadCacheTest : public ::testing::Test {
30 protected:
SetUp()31 void SetUp() override {
32 memory_ = new MemoryFake;
33 memory_cache_.reset(new MemoryThreadCache(memory_));
34
35 memory_->SetMemoryBlock(0x8000, 4096, 0xab);
36 memory_->SetMemoryBlock(0x9000, 4096, 0xde);
37 memory_->SetMemoryBlock(0xa000, 3000, 0x50);
38 }
39
40 MemoryFake* memory_;
41 std::unique_ptr<MemoryThreadCache> memory_cache_;
42
43 constexpr static size_t kMaxCachedSize = 64;
44 };
45
TEST_F(MemoryThreadCacheTest,cached_read)46 TEST_F(MemoryThreadCacheTest, cached_read) {
47 for (size_t i = 1; i <= kMaxCachedSize; i++) {
48 std::vector<uint8_t> buffer(i);
49 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
50 << "Read failed at size " << i;
51 ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
52 }
53
54 // Verify the cached data is used.
55 memory_->SetMemoryBlock(0x8000, 4096, 0xff);
56 for (size_t i = 1; i <= kMaxCachedSize; i++) {
57 std::vector<uint8_t> buffer(i);
58 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
59 << "Read failed at size " << i;
60 ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
61 }
62 }
63
TEST_F(MemoryThreadCacheTest,no_cached_read_after_clear)64 TEST_F(MemoryThreadCacheTest, no_cached_read_after_clear) {
65 for (size_t i = 1; i <= kMaxCachedSize; i++) {
66 std::vector<uint8_t> buffer(i);
67 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
68 << "Read failed at size " << i;
69 ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
70 }
71
72 // Verify the cached data is not used after a reset.
73 memory_cache_->Clear();
74 memory_->SetMemoryBlock(0x8000, 4096, 0xff);
75 for (size_t i = 1; i <= kMaxCachedSize; i++) {
76 std::vector<uint8_t> buffer(i);
77 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
78 << "Read failed at size " << i;
79 ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
80 }
81 }
82
TEST_F(MemoryThreadCacheTest,cached_read_across_caches)83 TEST_F(MemoryThreadCacheTest, cached_read_across_caches) {
84 std::vector<uint8_t> expect(16, 0xab);
85 expect.resize(32, 0xde);
86
87 std::vector<uint8_t> buffer(32);
88 ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
89 ASSERT_EQ(expect, buffer);
90
91 // Verify the cached data is used.
92 memory_->SetMemoryBlock(0x8000, 4096, 0xff);
93 memory_->SetMemoryBlock(0x9000, 4096, 0xff);
94 ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
95 ASSERT_EQ(expect, buffer);
96 }
97
TEST_F(MemoryThreadCacheTest,no_cache_read)98 TEST_F(MemoryThreadCacheTest, no_cache_read) {
99 for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
100 std::vector<uint8_t> buffer(i);
101 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
102 << "Read failed at size " << i;
103 ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
104 }
105
106 // Verify the cached data is not used.
107 memory_->SetMemoryBlock(0x8000, 4096, 0xff);
108 for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
109 std::vector<uint8_t> buffer(i);
110 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
111 << "Read failed at size " << i;
112 ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
113 }
114 }
115
TEST_F(MemoryThreadCacheTest,read_for_cache_fail)116 TEST_F(MemoryThreadCacheTest, read_for_cache_fail) {
117 std::vector<uint8_t> buffer(kMaxCachedSize);
118 ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
119 ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
120
121 // Verify the cached data is not used.
122 memory_->SetMemoryBlock(0xa000, 3000, 0xff);
123 ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
124 ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
125 }
126
TEST_F(MemoryThreadCacheTest,read_for_cache_fail_cross)127 TEST_F(MemoryThreadCacheTest, read_for_cache_fail_cross) {
128 std::vector<uint8_t> expect(16, 0xde);
129 expect.resize(32, 0x50);
130
131 std::vector<uint8_t> buffer(32);
132 ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
133 ASSERT_EQ(expect, buffer);
134
135 // Verify the cached data is not used for the second half but for the first.
136 memory_->SetMemoryBlock(0xa000, 3000, 0xff);
137 ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
138 expect.resize(16);
139 expect.resize(32, 0xff);
140 ASSERT_EQ(expect, buffer);
141 }
142
TEST_F(MemoryThreadCacheTest,read_cached_in_thread)143 TEST_F(MemoryThreadCacheTest, read_cached_in_thread) {
144 // Read from a different thread than this one.
145 std::thread thread([this] {
146 for (size_t i = 1; i <= kMaxCachedSize; i++) {
147 std::vector<uint8_t> buffer(i);
148 ASSERT_TRUE(this->memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
149 << "Read failed at size " << i;
150 ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
151 }
152 });
153
154 thread.join();
155
156 // Now modify the backing data, and read from the main thread verifying
157 // it is not using cached data.
158 memory_->SetMemoryBlock(0x8000, 4096, 0xff);
159 for (size_t i = 1; i <= kMaxCachedSize; i++) {
160 std::vector<uint8_t> buffer(i);
161 ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
162 << "Read failed at size " << i;
163 ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
164 }
165 }
166
ExhaustPthreadKeys(std::vector<pthread_key_t> * keys)167 static void ExhaustPthreadKeys(std::vector<pthread_key_t>* keys) {
168 // Use up all of the keys to force the next attempt to create one to fail.
169 static constexpr size_t kMaxKeysToCreate = 10000;
170 keys->resize(kMaxKeysToCreate);
171 for (size_t i = 0; i < kMaxKeysToCreate; i++) {
172 if (pthread_key_create(&(*keys)[i], nullptr) != 0) {
173 keys->resize(i);
174 break;
175 }
176 }
177 ASSERT_NE(0U, keys->size()) << "No keys created.";
178 ASSERT_LT(keys->size(), kMaxKeysToCreate) << "Cannot use up pthread keys.";
179 }
180
TEST_F(MemoryThreadCacheTest,read_uncached_due_to_error)181 TEST_F(MemoryThreadCacheTest, read_uncached_due_to_error) {
182 std::vector<pthread_key_t> keys;
183 ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
184
185 MemoryFake* fake = new MemoryFake;
186 MemoryThreadCache memory(fake);
187 fake->SetMemoryBlock(0x8000, 4096, 0xad);
188
189 // Read the data, which should be uncached.
190 uint8_t value;
191 ASSERT_TRUE(memory.ReadFully(0x8000, &value, 1));
192 ASSERT_EQ(0xad, value);
193 ASSERT_TRUE(memory.ReadFully(0x8001, &value, 1));
194 ASSERT_EQ(0xad, value);
195
196 // Verify the previous read did not cache anything.
197 fake->SetMemoryBlock(0x8000, 4096, 0x12);
198 ASSERT_TRUE(memory.ReadFully(0x8000, &value, 1));
199 ASSERT_EQ(0x12, value);
200 ASSERT_TRUE(memory.ReadFully(0x8001, &value, 1));
201 ASSERT_EQ(0x12, value);
202
203 for (pthread_key_t& key : keys) {
204 pthread_key_delete(key);
205 }
206 }
207
TEST_F(MemoryThreadCacheTest,clear_cache_when_no_cache)208 TEST_F(MemoryThreadCacheTest, clear_cache_when_no_cache) {
209 std::vector<pthread_key_t> keys;
210 ASSERT_NO_FATAL_FAILURE(ExhaustPthreadKeys(&keys));
211
212 MemoryFake* fake = new MemoryFake;
213 MemoryThreadCache memory(fake);
214 memory.Clear();
215
216 for (pthread_key_t& key : keys) {
217 pthread_key_delete(key);
218 }
219 }
220
221 } // namespace unwindstack
222