1 : // Copyright 2013 Google Inc. All Rights Reserved.
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 :
15 : #ifndef SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
16 : #define SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
17 :
18 : #include <string>
19 : #include <utility>
20 : #include <vector>
21 :
22 : #include "base/file_util.h"
23 : #include "base/files/scoped_temp_dir.h"
24 : #include "base/strings/string_piece.h"
25 : #include "gmock/gmock.h"
26 : #include "gtest/gtest.h"
27 : #include "syzygy/agent/asan/asan_logger.h"
28 : #include "syzygy/agent/asan/asan_runtime.h"
29 : #include "syzygy/agent/asan/error_info.h"
30 : #include "syzygy/agent/asan/heap.h"
31 : #include "syzygy/agent/asan/memory_notifier.h"
32 : #include "syzygy/agent/asan/stack_capture_cache.h"
33 : #include "syzygy/agent/asan/memory_notifiers/null_memory_notifier.h"
34 : #include "syzygy/core/unittest_util.h"
35 : #include "syzygy/trace/agent_logger/agent_logger.h"
36 : #include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"
37 :
38 : namespace testing {
39 :
40 : using agent::asan::AsanErrorInfo;
41 : using agent::asan::memory_notifiers::NullMemoryNotifier;
42 : using agent::asan::StackCaptureCache;
43 :
44 : // The default name of the runtime library DLL.
45 : extern const wchar_t kSyzyAsanRtlDll[];
46 :
47 : // A unittest fixture that ensures that an Asan logger instance is up and
48 : // running for the duration of the test. Output is captured to a file so that
49 : // its contents can be read after the test if necessary.
50 : class TestWithAsanLogger : public testing::Test {
51 : public:
52 : TestWithAsanLogger();
53 :
54 : // @name testing::Test overrides.
55 : // @{
56 : void SetUp() override;
57 : void TearDown() override;
58 : // @}
59 :
60 : // @name Accessors.
61 : // @{
62 : const std::wstring& instance_id() const { return instance_id_; }
63 : const base::FilePath& log_file_path() const { return log_file_path_; }
64 : const base::FilePath& temp_dir() const { return temp_dir_.path(); }
65 : // @}
66 :
67 : bool LogContains(const base::StringPiece& message);
68 :
69 : // Delete the temporary file used for the logging and its directory.
70 : void DeleteTempFileAndDirectory();
71 :
72 : // Starts the logger process.
73 : void StartLogger();
74 :
75 : // Stops the logger process.
76 : void StopLogger();
77 :
78 : // Reset the log contents.
79 : void ResetLog();
80 :
81 : // Appends @p instance to the RPC logger instance environment variable.
82 : void AppendToLoggerEnv(const std::string &instance);
83 :
84 : private:
85 : // The instance ID used by the running logger instance.
86 : std::wstring instance_id_;
87 :
88 : // The path to the log file where the the logger instance will write.
89 : base::FilePath log_file_path_;
90 :
91 : // Status of the logger process.
92 : bool logger_running_;
93 :
94 : // A temporary directory into which the log file will be written.
95 : base::ScopedTempDir temp_dir_;
96 :
97 : // The contents of the log. These are read by calling LogContains.
98 : bool log_contents_read_;
99 : std::string log_contents_;
100 :
101 : // Value of the logger instance environment variable before SetUp.
102 : std::string old_logger_env_;
103 :
104 : // Redirection files for the logger.
105 : base::ScopedFILE logger_stdin_file_;
106 : base::ScopedFILE logger_stdout_file_;
107 : base::ScopedFILE logger_stderr_file_;
108 : };
109 :
110 : // Shorthand for discussing all the asan runtime functions.
111 : #define ASAN_RTL_FUNCTIONS(F) \
112 : F(WINAPI, HANDLE, GetProcessHeap, (), ()) \
113 : F(WINAPI, HANDLE, HeapCreate, \
114 : (DWORD options, SIZE_T initial_size, SIZE_T maximum_size), \
115 : (options, initial_size, maximum_size)) \
116 : F(WINAPI, BOOL, HeapDestroy, \
117 : (HANDLE heap), (heap)) \
118 : F(WINAPI, LPVOID, HeapAlloc, \
119 : (HANDLE heap, DWORD flags, SIZE_T bytes), (heap, flags, bytes)) \
120 : F(WINAPI, LPVOID, HeapReAlloc, \
121 : (HANDLE heap, DWORD flags, LPVOID mem, SIZE_T bytes), \
122 : (heap, flags, mem, bytes)) \
123 : F(WINAPI, BOOL, HeapFree, \
124 : (HANDLE heap, DWORD flags, LPVOID mem), (heap, flags, mem)) \
125 : F(WINAPI, SIZE_T, HeapSize, \
126 : (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem)) \
127 : F(WINAPI, BOOL, HeapValidate, \
128 : (HANDLE heap, DWORD flags, LPCVOID mem), (heap, flags, mem)) \
129 : F(WINAPI, SIZE_T, HeapCompact, \
130 : (HANDLE heap, DWORD flags), (heap, flags)) \
131 : F(WINAPI, BOOL, HeapLock, (HANDLE heap), (heap)) \
132 : F(WINAPI, BOOL, HeapUnlock, (HANDLE heap), (heap)) \
133 : F(WINAPI, BOOL, HeapWalk, \
134 : (HANDLE heap, LPPROCESS_HEAP_ENTRY entry), (heap, entry)) \
135 : F(WINAPI, BOOL, HeapSetInformation, \
136 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
137 : PVOID info, SIZE_T info_length), \
138 : (heap, info_class, info, info_length)) \
139 : F(WINAPI, BOOL, HeapQueryInformation, \
140 : (HANDLE heap, HEAP_INFORMATION_CLASS info_class, \
141 : PVOID info, SIZE_T info_length, PSIZE_T return_length), \
142 : (heap, info_class, info, info_length, return_length)) \
143 : F(WINAPI, void, SetCallBack, \
144 : (void (*callback)(AsanErrorInfo* error_info)), \
145 : (callback)) \
146 : F(_cdecl, void*, memcpy, \
147 : (void* destination, const void* source, size_t num), \
148 : (destination, source, num)) \
149 : F(_cdecl, void*, memmove, \
150 : (void* destination, const void* source, size_t num), \
151 : (destination, source, num)) \
152 : F(_cdecl, void*, memset, (void* ptr, int value, size_t num), \
153 : (ptr, value, num)) \
154 : F(_cdecl, const void*, memchr, (const void* ptr, int value, size_t num), \
155 : (ptr, value, num)) \
156 : F(_cdecl, size_t, strcspn, (const char* str1, const char* str2), \
157 : (str1, str2)) \
158 : F(_cdecl, size_t, strlen, (const char* str), (str)) \
159 : F(_cdecl, const char*, strrchr, (const char* str, int character), \
160 : (str, character)) \
161 : F(_cdecl, const wchar_t*, wcsrchr, (const wchar_t* str, int character), \
162 : (str, character)) \
163 : F(_cdecl, const wchar_t*, wcschr, (const wchar_t* str, int character), \
164 : (str, character)) \
165 : F(_cdecl, int, strcmp, (const char* str1, const char* str2), \
166 : (str1, str2)) \
167 : F(_cdecl, const char*, strpbrk, (const char* str1, const char* str2), \
168 : (str1, str2)) \
169 : F(_cdecl, const char*, strstr, (const char* str1, const char* str2), \
170 : (str1, str2)) \
171 : F(_cdecl, const wchar_t*, wcsstr, (const wchar_t* str1, \
172 : const wchar_t* str2), (str1, str2)) \
173 : F(_cdecl, size_t, strspn, (const char* str1, const char* str2), \
174 : (str1, str2)) \
175 : F(_cdecl, char*, strncpy, \
176 : (char* destination, const char* source, size_t num), \
177 : (destination, source, num)) \
178 : F(_cdecl, char*, strncat, \
179 : (char* destination, const char* source, size_t num), \
180 : (destination, source, num)) \
181 : F(WINAPI, BOOL, ReadFile, \
182 : (HANDLE file_handle, LPVOID buffer, DWORD bytes_to_read, \
183 : LPDWORD bytes_read, LPOVERLAPPED overlapped), \
184 : (file_handle, buffer, bytes_to_read, bytes_read, overlapped)) \
185 : F(WINAPI, BOOL, WriteFile, \
186 : (HANDLE file_handle, LPCVOID buffer, DWORD bytes_to_write, \
187 : LPDWORD bytes_written, LPOVERLAPPED overlapped), \
188 : (file_handle, buffer, bytes_to_write, bytes_written, overlapped)) \
189 : F(_cdecl, void, SetInterceptorCallback, (void (*callback)()), (callback)) \
190 : F(WINAPI, agent::asan::AsanRuntime*, GetActiveRuntime, (), ()) \
191 : F(WINAPI, void, SetAllocationFilterFlag, (), ()) \
192 : F(WINAPI, void, ClearAllocationFilterFlag, (), ())
193 :
194 : // Declare pointer types for the intercepted functions.
195 : #define DECLARE_ASAN_FUNCTION_PTR(convention, ret, name, args, argnames) \
196 : typedef ret (convention* name##FunctionPtr)args;
197 : ASAN_RTL_FUNCTIONS(DECLARE_ASAN_FUNCTION_PTR)
198 : #undef DECLARE_ASAN_FUNCTION_PTR
199 :
200 : class TestAsanRtl : public testing::TestWithAsanLogger {
201 : public:
202 E : TestAsanRtl() : asan_rtl_(NULL), heap_(NULL) {
203 E : }
204 :
205 E : void SetUp() override {
206 E : testing::TestWithAsanLogger::SetUp();
207 :
208 : // Load the Asan runtime library.
209 : base::FilePath asan_rtl_path =
210 E : testing::GetExeRelativePath(L"syzyasan_rtl.dll");
211 E : asan_rtl_ = ::LoadLibrary(asan_rtl_path.value().c_str());
212 E : ASSERT_TRUE(asan_rtl_ != NULL);
213 :
214 : // Load all the functions and assert that we find them.
215 : #define LOAD_ASAN_FUNCTION(convention, ret, name, args, argnames) \
216 : name##Function = reinterpret_cast<name##FunctionPtr>( \
217 : ::GetProcAddress(asan_rtl_, "asan_" #name)); \
218 : ASSERT_TRUE(name##Function != NULL);
219 :
220 E : ASAN_RTL_FUNCTIONS(LOAD_ASAN_FUNCTION)
221 :
222 : #undef LOAD_ASAN_FUNCTION
223 :
224 E : heap_ = HeapCreateFunction(0, 0, 0);
225 E : ASSERT_TRUE(heap_ != NULL);
226 :
227 E : agent::asan::AsanRuntime* runtime = GetActiveRuntimeFunction();
228 E : ASSERT_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime);
229 : // Disable the heap checking as this really slows down the unittests.
230 E : runtime->params().check_heap_on_failure = false;
231 E : }
232 :
233 E : void TearDown() override {
234 E : if (heap_ != NULL) {
235 E : HeapDestroyFunction(heap_);
236 E : heap_ = NULL;
237 : }
238 :
239 E : if (asan_rtl_ != NULL) {
240 E : ::FreeLibrary(asan_rtl_);
241 E : asan_rtl_ = NULL;
242 : }
243 :
244 E : testing::TestWithAsanLogger::TearDown();
245 E : }
246 :
247 E : HANDLE heap() { return heap_; }
248 :
249 : // Declare pointers to intercepted functions.
250 : #define DECLARE_FUNCTION_PTR_VARIABLE(convention, ret, name, args, argnames) \
251 : static name##FunctionPtr name##Function;
252 : ASAN_RTL_FUNCTIONS(DECLARE_FUNCTION_PTR_VARIABLE)
253 : #undef DECLARE_FUNCTION_PTR_VARIABLE
254 :
255 : // Define versions of all of the functions that expect an error to be thrown
256 : // by the AsanErrorCallback, and in turn raise an exception if the underlying
257 : // function didn't fail.
258 : #define DECLARE_FAILING_FUNCTION(convention, ret, name, args, argnames) \
259 : static void name##FunctionFailing args;
260 : ASAN_RTL_FUNCTIONS(DECLARE_FAILING_FUNCTION)
261 : #undef DECLARE_FAILING_FUNCTION
262 :
263 : protected:
264 : // The AsanAsan runtime module to test.
265 : HMODULE asan_rtl_;
266 :
267 : // Scratch heap handle valid from SetUp to TearDown.
268 : HANDLE heap_;
269 : };
270 :
271 : // A helper struct to be passed as a destructor of Asan scoped allocation.
272 : struct AsanDeleteHelper {
273 E : explicit AsanDeleteHelper(TestAsanRtl* asan_rtl)
274 : : asan_rtl_(asan_rtl) {
275 E : }
276 :
277 E : void operator()(void* ptr) {
278 E : asan_rtl_->HeapFreeFunction(asan_rtl_->heap(), 0, ptr);
279 E : }
280 : TestAsanRtl* asan_rtl_;
281 : };
282 :
283 : // A scoped_ptr specialization for the Asan allocations.
284 : template <typename T>
285 : class ScopedAsanAlloc : public scoped_ptr<T, AsanDeleteHelper> {
286 : public:
287 : explicit ScopedAsanAlloc(TestAsanRtl* asan_rtl)
288 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
289 : }
290 :
291 E : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size)
292 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
293 E : Allocate(asan_rtl, size);
294 E : }
295 :
296 E : ScopedAsanAlloc(TestAsanRtl* asan_rtl, size_t size, const T* value)
297 : : scoped_ptr(NULL, AsanDeleteHelper(asan_rtl)) {
298 E : Allocate(asan_rtl, size);
299 E : ::memcpy(get(), value, size * sizeof(T));
300 E : }
301 :
302 : template <typename T2>
303 E : T2* GetAs() {
304 E : return reinterpret_cast<T2*>(get());
305 E : }
306 :
307 E : void Allocate(TestAsanRtl* asan_rtl, size_t size) {
308 E : ASSERT_TRUE(asan_rtl != NULL);
309 : reset(reinterpret_cast<T*>(
310 E : asan_rtl->HeapAllocFunction(asan_rtl->heap(), 0, size * sizeof(T))));
311 E : ::memset(get(), 0, size * sizeof(T));
312 E : }
313 :
314 : T operator[](int i) const {
315 : CHECK(get() != NULL);
316 : return get()[i];
317 : }
318 :
319 E : T& operator[](int i) {
320 E : CHECK(get() != NULL);
321 E : return get()[i];
322 E : }
323 : };
324 :
325 : // A unittest fixture that initializes an Asan runtime instance.
326 : class TestWithAsanRuntime : public testing::Test {
327 : public:
328 E : TestWithAsanRuntime() {
329 E : runtime_ = new agent::asan::AsanRuntime();
330 E : owns_runtime_ = true;
331 E : }
332 :
333 E : explicit TestWithAsanRuntime(agent::asan::AsanRuntime* runtime)
334 : : runtime_(runtime), owns_runtime_(false) {
335 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
336 E : }
337 :
338 E : ~TestWithAsanRuntime() {
339 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
340 E : if (owns_runtime_)
341 E : delete runtime_;
342 E : runtime_ = NULL;
343 E : }
344 :
345 E : virtual void SetUp() override {
346 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
347 E : testing::Test::SetUp();
348 E : runtime_->SetUp(L"");
349 E : }
350 :
351 E : virtual void TearDown() override {
352 E : CHECK_NE(reinterpret_cast<agent::asan::AsanRuntime*>(NULL), runtime_);
353 E : runtime_->TearDown();
354 E : testing::Test::TearDown();
355 E : }
356 :
357 : protected:
358 : // The runtime instance used by the tests.
359 : agent::asan::AsanRuntime* runtime_;
360 :
361 : // Indicates if we own the runtime instance.
362 : bool owns_runtime_;
363 : };
364 :
365 : // A unittest fixture to test the bookkeeping functions.
366 : struct FakeAsanBlock {
367 : static const size_t kMaxAlignmentLog = 13;
368 : static const size_t kMaxAlignment = 1 << kMaxAlignmentLog;
369 : // If we want to test the alignments up to 4096 we need a buffer of at least
370 : // 3 * 4096 bytes:
371 : // +--- 0 <= size < 4096 bytes---+---4096 bytes---+--4096 bytes--+
372 : // ^buffer ^aligned_buffer ^user_pointer
373 : static const size_t kBufferSize = 3 * kMaxAlignment;
374 : static const uint8 kBufferHeaderValue = 0xAE;
375 : static const uint8 kBufferTrailerValue = 0xEA;
376 :
377 : FakeAsanBlock(size_t alloc_alignment_log, StackCaptureCache* stack_cache);
378 :
379 : ~FakeAsanBlock();
380 :
381 : // Initialize an Asan block in the buffer.
382 : // @param alloc_size The user size of the Asan block.
383 : // @returns true on success, false otherwise.
384 : bool InitializeBlock(size_t alloc_size);
385 :
386 : // Ensures that this block has a valid block header.
387 : bool TestBlockMetadata();
388 :
389 : // Mark the current Asan block as quarantined.
390 : bool MarkBlockAsQuarantined();
391 :
392 : // The buffer we use internally.
393 : uint8 buffer[kBufferSize];
394 :
395 : // The information about the block once it has been initialized.
396 : agent::asan::BlockInfo block_info;
397 :
398 : // The alignment of the current allocation.
399 : size_t alloc_alignment;
400 : size_t alloc_alignment_log;
401 :
402 : // The sizes of the different sub-structures in the buffer.
403 : size_t buffer_header_size;
404 : size_t buffer_trailer_size;
405 :
406 : // The pointers to the different sub-structures in the buffer.
407 : uint8* buffer_align_begin;
408 :
409 : // Indicate if the buffer has been initialized.
410 : bool is_initialized;
411 :
412 : // The cache that will store the stack traces of this block.
413 : StackCaptureCache* stack_cache;
414 : };
415 :
416 : // A mock memory notifier. Useful when testing objects that have a memory
417 : // notifier dependency.
418 : class MockMemoryNotifier : public agent::asan::MemoryNotifierInterface {
419 : public:
420 : // Constructor.
421 E : MockMemoryNotifier() { }
422 :
423 : // Virtual destructor.
424 E : virtual ~MockMemoryNotifier() { }
425 :
426 : // @name MemoryNotifierInterface implementation.
427 : // @{
428 E : MOCK_METHOD2(NotifyInternalUse, void(const void*, size_t));
429 E : MOCK_METHOD2(NotifyFutureHeapUse, void(const void*, size_t));
430 E : MOCK_METHOD2(NotifyReturnedToOS, void(const void*, size_t));
431 : // @}
432 :
433 : private:
434 : DISALLOW_COPY_AND_ASSIGN(MockMemoryNotifier);
435 : };
436 :
437 : // A mock HeapInterface.
438 : class LenientMockHeap : public agent::asan::HeapInterface {
439 : public:
440 E : LenientMockHeap() { }
441 E : virtual ~LenientMockHeap() { }
442 i : MOCK_CONST_METHOD0(GetHeapType, agent::asan::HeapType());
443 E : MOCK_CONST_METHOD0(GetHeapFeatures, uint32());
444 E : MOCK_METHOD1(Allocate, void*(size_t));
445 E : MOCK_METHOD1(Free, bool(void*));
446 i : MOCK_METHOD1(IsAllocated, bool(const void*));
447 i : MOCK_METHOD1(GetAllocationSize, size_t(const void*));
448 i : MOCK_METHOD0(Lock, void());
449 i : MOCK_METHOD0(Unlock, void());
450 i : MOCK_METHOD0(TryLock, bool());
451 : };
452 : typedef testing::StrictMock<LenientMockHeap> MockHeap;
453 :
454 : typedef std::vector<agent::asan::AsanBlockInfo> AsanBlockInfoVector;
455 : typedef std::pair<agent::asan::AsanCorruptBlockRange, AsanBlockInfoVector>
456 : CorruptRangeInfo;
457 : typedef std::vector<CorruptRangeInfo> CorruptRangeVector;
458 :
459 : // A helper for testing SyzyAsan memory accessor instrumentation functions.
460 : class MemoryAccessorTester {
461 : public:
462 : typedef agent::asan::BadAccessKind BadAccessKind;
463 :
464 : enum IgnoreFlags {
465 : IGNORE_FLAGS
466 : };
467 : MemoryAccessorTester();
468 : explicit MemoryAccessorTester(IgnoreFlags ignore_flags);
469 : ~MemoryAccessorTester();
470 :
471 : // Checks that @p access_fn doesn't raise exceptions on access checking
472 : // @p ptr, and that @p access_fn doesn't modify any registers or flags
473 : // when executed.
474 : void CheckAccessAndCompareContexts(FARPROC access_fn, void* ptr);
475 :
476 : // Checks that @p access_fn generates @p bad_access_type on checking @p ptr.
477 : void AssertMemoryErrorIsDetected(
478 : FARPROC access_fn, void* ptr, BadAccessKind bad_access_type);
479 :
480 : enum StringOperationDirection {
481 : DIRECTION_FORWARD,
482 : DIRECTION_BACKWARD
483 : };
484 : // Checks that @p access_fn doesn't raise exceptions on access checking
485 : // for a given @p direction, @p src, @p dst and @p len.
486 : void CheckSpecialAccessAndCompareContexts(
487 : FARPROC access_fn, StringOperationDirection direction,
488 : void* dst, void* src, int len);
489 :
490 : // Checks that @p access_fn generates @p bad_access_type on access checking
491 : // for a given @p direction, @p src, @p dst and @p len.
492 : void ExpectSpecialMemoryErrorIsDetected(
493 : FARPROC access_fn, StringOperationDirection direction,
494 : bool expect_error, void* dst, void* src, int32 length,
495 : BadAccessKind bad_access_type);
496 :
497 : static void AsanErrorCallback(AsanErrorInfo* error_info);
498 :
499 E : void set_expected_error_type(BadAccessKind expected) {
500 E : expected_error_type_ = expected;
501 E : }
502 E : bool memory_error_detected() const { return memory_error_detected_; }
503 E : void set_memory_error_detected(bool memory_error_detected) {
504 E : memory_error_detected_ = memory_error_detected;
505 E : }
506 :
507 E : const AsanErrorInfo& last_error_info() const { return last_error_info_; }
508 E : const CorruptRangeVector& last_corrupt_ranges() const {
509 E : return last_corrupt_ranges_;
510 E : }
511 :
512 : private:
513 : void Initialize();
514 : void AsanErrorCallbackImpl(AsanErrorInfo* error_info);
515 :
516 : // This will be used in the asan callback to ensure that we detect the right
517 : // error.
518 : BadAccessKind expected_error_type_;
519 : // A flag used in asan callback to ensure that a memory error has been
520 : // detected.
521 : bool memory_error_detected_;
522 :
523 : // Indicates whether to ignore changes to the flags register.
524 : bool ignore_flags_;
525 :
526 : // The pre- and post-invocation contexts.
527 : CONTEXT context_before_hook_;
528 : CONTEXT context_after_hook_;
529 : // Context captured on error.
530 : CONTEXT error_context_;
531 :
532 : // The information about the last error.
533 : AsanErrorInfo last_error_info_;
534 : CorruptRangeVector last_corrupt_ranges_;
535 :
536 : // There shall be only one!
537 : static MemoryAccessorTester* instance_;
538 : };
539 :
540 : // A fixture class for testing memory interceptors.
541 : class TestMemoryInterceptors : public TestWithAsanLogger {
542 : public:
543 : // Redefine some enums for local use.
544 : enum AccessMode {
545 : AsanReadAccess = agent::asan::ASAN_READ_ACCESS,
546 : AsanWriteAccess = agent::asan::ASAN_WRITE_ACCESS,
547 : AsanUnknownAccess = agent::asan::ASAN_UNKNOWN_ACCESS,
548 : };
549 :
550 : struct InterceptFunction {
551 : void(*function)();
552 : size_t size;
553 : };
554 :
555 : struct StringInterceptFunction {
556 : void(*function)();
557 : size_t size;
558 : AccessMode dst_access_mode;
559 : AccessMode src_access_mode;
560 : bool uses_counter;
561 : };
562 :
563 : static const bool kCounterInit_ecx = true;
564 : static const bool kCounterInit_1 = false;
565 :
566 : TestMemoryInterceptors();
567 : void SetUp() override;
568 : void TearDown() override;
569 :
570 : template <size_t N>
571 E : void TestValidAccess(const InterceptFunction (&fns)[N]) {
572 E : TestValidAccess(fns, N);
573 E : }
574 : template <size_t N>
575 E : void TestValidAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
576 E : TestValidAccessIgnoreFlags(fns, N);
577 E : }
578 : template <size_t N>
579 E : void TestOverrunAccess(const InterceptFunction (&fns)[N]) {
580 E : TestOverrunAccess(fns, N);
581 E : }
582 : template <size_t N>
583 E : void TestOverrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
584 E : TestOverrunAccessIgnoreFlags(fns, N);
585 E : }
586 : template <size_t N>
587 E : void TestUnderrunAccess(const InterceptFunction (&fns)[N]) {
588 E : TestUnderrunAccess(fns, N);
589 E : }
590 : template <size_t N>
591 E : void TestUnderrunAccessIgnoreFlags(const InterceptFunction (&fns)[N]) {
592 E : TestUnderrunAccessIgnoreFlags(fns, N);
593 E : }
594 : template <size_t N>
595 E : void TestStringValidAccess(const StringInterceptFunction (&fns)[N]) {
596 E : TestStringValidAccess(fns, N);
597 E : }
598 : template <size_t N>
599 E : void TestStringOverrunAccess(const StringInterceptFunction (&fns)[N]) {
600 E : TestStringOverrunAccess(fns, N);
601 E : }
602 :
603 : protected:
604 : void TestValidAccess(const InterceptFunction* fns, size_t num_fns);
605 : void TestValidAccessIgnoreFlags(const InterceptFunction* fns,
606 : size_t num_fns);
607 : void TestOverrunAccess(const InterceptFunction* fns, size_t num_fns);
608 : void TestOverrunAccessIgnoreFlags(const InterceptFunction* fns,
609 : size_t num_fns);
610 : void TestUnderrunAccess(const InterceptFunction* fns, size_t num_fns);
611 : void TestUnderrunAccessIgnoreFlags(const InterceptFunction* fns,
612 : size_t num_fns);
613 : void TestStringValidAccess(
614 : const StringInterceptFunction* fns, size_t num_fns);
615 : void TestStringOverrunAccess(
616 : const StringInterceptFunction* fns, size_t num_fns);
617 :
618 : const size_t kAllocSize = 64;
619 :
620 : agent::asan::AsanRuntime asan_runtime_;
621 : HANDLE heap_;
622 :
623 : // Convenience allocs of kAllocSize. Valid from SetUp to TearDown.
624 : byte* src_;
625 : byte* dst_;
626 : };
627 :
628 : // A very lightweight dummy heap to be used in stress testing the
629 : // HeapAllocator. Lock and Unlock are noops, so this is not thread
630 : // safe.
631 : class DummyHeap : public agent::asan::HeapInterface {
632 : public:
633 E : virtual ~DummyHeap() { }
634 i : virtual agent::asan::HeapType GetHeapType() const {
635 i : return agent::asan::kUnknownHeapType;
636 i : }
637 E : virtual uint32 GetHeapFeatures() const { return 0; }
638 E : virtual void* Allocate(size_t bytes) { return ::malloc(bytes); }
639 E : virtual bool Free(void* alloc) { ::free(alloc); return true; }
640 i : virtual bool IsAllocated(const void* alloc) { return false; }
641 i : virtual size_t GetAllocationSize(const void* alloc) { return 0; }
642 E : virtual void Lock() { return; }
643 E : virtual void Unlock() { return; }
644 E : virtual bool TryLock() { return true; }
645 : };
646 :
647 : // Test read and write access.
648 : // Use carefully, since it will try to overwrite the value at @p address with 0.
649 : // @returns true if the address is readable and writable, false otherwise.
650 : bool IsAccessible(void* address);
651 :
652 : // Test read and write access.
653 : // Use carefully, since it will try to overwrite the value at @p address with 0.
654 : // @returns true if the address is neither readable nor writable,
655 : // false otherwise.
656 : bool IsNotAccessible(void* address);
657 :
658 : } // namespace testing
659 :
660 : #endif // SYZYGY_AGENT_ASAN_UNITTEST_UTIL_H_
|