1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : #include "syzygy/agent/asan/asan_heap.h"
15 :
16 : #include "base/compiler_specific.h"
17 : #include "base/logging.h"
18 : #include "base/rand_util.h"
19 : #include "base/sha1.h"
20 : #include "base/debug/debugger.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/agent/asan/asan_shadow.h"
23 :
24 : namespace agent {
25 : namespace asan {
26 :
27 : namespace {
28 :
29 : class HeapTest : public testing::Test {
30 : public:
31 E : virtual void SetUp() OVERRIDE {
32 E : ASSERT_TRUE(proxy_.Create(0, 0, 0));
33 E : }
34 :
35 E : virtual void TearDown() OVERRIDE {
36 E : ASSERT_TRUE(proxy_.Destroy());
37 E : }
38 :
39 : // Verifies that [alloc, alloc + size) is accessible, and that
40 : // [alloc - 1] and [alloc+size] are poisoned.
41 E : void VerifyAllocAccess(void* alloc, size_t size) {
42 E : uint8* mem = reinterpret_cast<uint8*>(alloc);
43 E : ASSERT_FALSE(Shadow::IsAccessible(mem - 1));
44 E : for (size_t i = 0; i < size; ++i)
45 E : ASSERT_TRUE(Shadow::IsAccessible(mem + i));
46 E : ASSERT_FALSE(Shadow::IsAccessible(mem + size));
47 E : }
48 :
49 : // Verifies that [alloc-1, alloc+size] is poisoned.
50 E : void VerifyFreedAccess(void* alloc, size_t size) {
51 E : uint8* mem = reinterpret_cast<uint8*>(alloc);
52 E : ASSERT_FALSE(Shadow::IsAccessible(mem - 1));
53 E : for (size_t i = 0; i < size; ++i)
54 E : ASSERT_FALSE(Shadow::IsAccessible(mem + i));
55 E : ASSERT_FALSE(Shadow::IsAccessible(mem + size));
56 E : }
57 :
58 E : void RandomSetMemory(void* alloc, size_t size) {
59 E : base::RandBytes(alloc, size);
60 E : }
61 :
62 : protected:
63 : // Arbitrary constant for all size limit.
64 : static const size_t kMaxAllocSize = 134584;
65 :
66 : HeapProxy proxy_;
67 : };
68 :
69 : } // namespace
70 :
71 E : TEST_F(HeapTest, ToFromHandle) {
72 E : HANDLE handle = HeapProxy::ToHandle(&proxy_);
73 E : ASSERT_TRUE(handle != NULL);
74 E : ASSERT_EQ(&proxy_, HeapProxy::FromHandle(handle));
75 E : }
76 :
77 E : TEST_F(HeapTest, AllocFree) {
78 E : const size_t kAllocSize = 100;
79 E : LPVOID mem = proxy_.Alloc(0, kAllocSize);
80 E : ASSERT_TRUE(mem != NULL);
81 E : ASSERT_EQ(kAllocSize, proxy_.Size(0, mem));
82 E : const size_t kReAllocSize = 2 * kAllocSize;
83 E : mem = proxy_.ReAlloc(0, mem, kReAllocSize);
84 E : ASSERT_EQ(kReAllocSize, proxy_.Size(0, mem));
85 E : ASSERT_TRUE(proxy_.Free(0, mem));
86 E : }
87 :
88 E : TEST_F(HeapTest, AllocsAccessibility) {
89 E : for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
90 : // Do an alloc/realloc/free and test that access is correctly managed.
91 E : void* mem = proxy_.Alloc(0, size);
92 E : ASSERT_TRUE(mem != NULL);
93 E : ASSERT_NO_FATAL_FAILURE(VerifyAllocAccess(mem, size));
94 E : RandomSetMemory(mem, size);
95 :
96 E : size_t new_size = size;
97 E : while (new_size == size)
98 E : new_size = base::RandInt(size / 2, size * 2);
99 :
100 E : unsigned char sha1_before[base::kSHA1Length] = {};
101 : base::SHA1HashBytes(reinterpret_cast<unsigned char*>(mem),
102 : std::min(size, new_size),
103 E : sha1_before);
104 :
105 E : void* new_mem = proxy_.ReAlloc(0, mem, size * 2);
106 E : ASSERT_TRUE(new_mem != NULL);
107 E : ASSERT_NE(mem, new_mem);
108 :
109 E : unsigned char sha1_after[base::kSHA1Length] = {};
110 : base::SHA1HashBytes(reinterpret_cast<unsigned char*>(new_mem),
111 : std::min(size, new_size),
112 E : sha1_after);
113 E : ASSERT_EQ(0, memcmp(sha1_before, sha1_after, base::kSHA1Length));
114 :
115 E : ASSERT_NO_FATAL_FAILURE(VerifyFreedAccess(mem, size));
116 E : ASSERT_NO_FATAL_FAILURE(VerifyAllocAccess(new_mem, size * 2));
117 :
118 E : ASSERT_TRUE(proxy_.Free(0, new_mem));
119 E : ASSERT_NO_FATAL_FAILURE(VerifyFreedAccess(new_mem, size * 2));
120 E : }
121 E : }
122 :
123 E : TEST_F(HeapTest, Size) {
124 E : for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
125 E : void* mem = proxy_.Alloc(0, size);
126 E : ASSERT_FALSE(mem == NULL);
127 E : ASSERT_EQ(size, proxy_.Size(0, mem));
128 E : ASSERT_TRUE(proxy_.Free(0, mem));
129 E : }
130 E : }
131 :
132 E : TEST_F(HeapTest, Validate) {
133 E : for (size_t size = 10; size < kMaxAllocSize; size = size * 5 + 123) {
134 E : void* mem = proxy_.Alloc(0, size);
135 E : ASSERT_FALSE(mem == NULL);
136 E : ASSERT_TRUE(proxy_.Validate(0, mem));
137 E : ASSERT_TRUE(proxy_.Free(0, mem));
138 E : }
139 E : }
140 :
141 E : TEST_F(HeapTest, Compact) {
142 : // Compact should return a non-zero size.
143 E : ASSERT_LT(0U, proxy_.Compact(0));
144 :
145 : // TODO(siggi): It may not be possible to allocate the size returned due
146 : // to padding - fix and test.
147 E : }
148 :
149 E : TEST_F(HeapTest, LockUnlock) {
150 : // We can't really test these, aside from not crashing.
151 E : ASSERT_TRUE(proxy_.Lock());
152 E : ASSERT_TRUE(proxy_.Unlock());
153 E : }
154 :
155 E : TEST_F(HeapTest, Walk) {
156 : // We assume at least two entries to walk through.
157 E : PROCESS_HEAP_ENTRY entry = {};
158 E : ASSERT_TRUE(proxy_.Walk(&entry));
159 E : ASSERT_TRUE(proxy_.Walk(&entry));
160 E : }
161 :
162 E : TEST_F(HeapTest, SetQueryInformation) {
163 E : ULONG compat_flag = -1;
164 E : unsigned long ret = 0;
165 : // Get the current value of the compat flag.
166 : ASSERT_TRUE(
167 : proxy_.QueryInformation(HeapCompatibilityInformation,
168 E : &compat_flag, sizeof(compat_flag), &ret));
169 E : ASSERT_EQ(sizeof(compat_flag), ret);
170 E : ASSERT_TRUE(compat_flag != -1);
171 :
172 : // Put the heap in LFH, which should always succeed, except when a debugger
173 : // is attached. When a debugger is attached, the heap is wedged in certain
174 : // debug settings.
175 E : if (base::debug::BeingDebugged()) {
176 i : LOG(WARNING) << "Can't test HeapProxy::SetInformation under debugger.";
177 i : return;
178 : }
179 :
180 E : compat_flag = 2;
181 : ASSERT_TRUE(
182 : proxy_.SetInformation(HeapCompatibilityInformation,
183 E : &compat_flag, sizeof(compat_flag)));
184 E : }
185 :
186 : } // namespace asan
187 : } // namespace agent
|