1 : // Copyright 2014 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 : // Memory Profiler unittests.
16 :
17 : #include "syzygy/agent/memprof/memprof.h"
18 :
19 : #include <windows.h>
20 :
21 : #include "base/file_util.h"
22 : #include "base/scoped_native_library.h"
23 : #include "base/files/file_enumerator.h"
24 : #include "base/files/scoped_temp_dir.h"
25 : #include "base/message_loop/message_loop.h"
26 : #include "base/threading/platform_thread.h"
27 : #include "base/threading/thread.h"
28 : #include "gmock/gmock.h"
29 : #include "gtest/gtest.h"
30 : #include "syzygy/agent/common/process_utils.h"
31 : #include "syzygy/core/unittest_util.h"
32 : #include "syzygy/pe/unittest_util.h"
33 : #include "syzygy/trace/common/unittest_util.h"
34 : #include "syzygy/trace/parse/parser.h"
35 : #include "syzygy/trace/parse/unittest_util.h"
36 : #include "syzygy/trace/protocol/call_trace_defs.h"
37 : #include "syzygy/trace/service/service.h"
38 : #include "syzygy/trace/service/service_rpc_impl.h"
39 :
40 : namespace agent {
41 : namespace memprof {
42 :
43 : namespace {
44 :
45 : using agent::common::GetProcessModules;
46 : using agent::common::ModuleVector;
47 : using testing::_;
48 : using testing::AllOf;
49 : using testing::Return;
50 : using testing::StrictMockParseEventHandler;
51 : using trace::service::RpcServiceInstanceManager;
52 : using trace::service::Service;
53 : using trace::parser::Parser;
54 : using trace::parser::ParseEventHandler;
55 :
56 : // Function pointers for various Heap API functions.
57 : typedef HANDLE (WINAPI *HeapCreatePtr)(DWORD, SIZE_T, SIZE_T);
58 : typedef BOOL (WINAPI *HeapDestroyPtr)(HANDLE);
59 : typedef LPVOID (WINAPI *HeapAllocPtr)(HANDLE, DWORD, SIZE_T);
60 : typedef BOOL (WINAPI *HeapFreePtr)(HANDLE, DWORD, LPVOID);
61 :
62 : class MemoryProfilerTest : public testing::Test {
63 : public:
64 : MemoryProfilerTest()
65 : : module_(nullptr),
66 : heap_create_(nullptr),
67 : heap_destroy_(nullptr),
68 : heap_alloc_(nullptr),
69 E : heap_free_(nullptr) {
70 E : }
71 :
72 E : virtual void SetUp() OVERRIDE {
73 E : testing::Test::SetUp();
74 :
75 : // Create a temporary directory for the call trace files.
76 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
77 :
78 E : service_.SetEnvironment();
79 E : }
80 :
81 E : virtual void TearDown() OVERRIDE {
82 E : UnloadDll();
83 :
84 : // Stop the call trace service.
85 E : service_.Stop();
86 E : }
87 :
88 E : void StartService() {
89 E : service_.Start(temp_dir_.path());
90 E : }
91 :
92 E : void StopService() {
93 E : service_.Stop();
94 E : }
95 :
96 E : void ReplayLogs() {
97 : // Stop the service if it's running.
98 E : ASSERT_NO_FATAL_FAILURE(StopService());
99 :
100 E : Parser parser;
101 E : ASSERT_TRUE(parser.Init(&handler_));
102 :
103 : // Queue up the trace file(s) we engendered.
104 : base::FileEnumerator enumerator(temp_dir_.path(),
105 : false,
106 E : base::FileEnumerator::FILES);
107 E : size_t num_files = 0;
108 E : while (true) {
109 E : base::FilePath trace_file = enumerator.Next();
110 E : if (trace_file.empty())
111 E : break;
112 E : ASSERT_TRUE(parser.OpenTraceFile(trace_file));
113 E : ++num_files;
114 E : }
115 E : EXPECT_GT(num_files, 0U);
116 E : ASSERT_TRUE(parser.Consume());
117 E : }
118 :
119 E : void LoadDll() {
120 E : ASSERT_TRUE(module_ == NULL);
121 : static const wchar_t kClientDll[] = L"memprof.dll";
122 E : ASSERT_EQ(NULL, ::GetModuleHandle(kClientDll));
123 E : module_ = ::LoadLibrary(kClientDll);
124 E : ASSERT_TRUE(module_ != nullptr);
125 :
126 : heap_create_ = reinterpret_cast<HeapCreatePtr>(
127 E : ::GetProcAddress(module_, "asan_HeapCreate"));
128 E : ASSERT_TRUE(heap_create_ != nullptr);
129 : heap_destroy_ = reinterpret_cast<HeapDestroyPtr>(
130 E : ::GetProcAddress(module_, "asan_HeapDestroy"));
131 E : ASSERT_TRUE(heap_destroy_ != nullptr);
132 : heap_alloc_ = reinterpret_cast<HeapAllocPtr>(
133 E : ::GetProcAddress(module_, "asan_HeapAlloc"));
134 E : ASSERT_TRUE(heap_alloc_ != nullptr);
135 : heap_free_ = reinterpret_cast<HeapFreePtr>(
136 E : ::GetProcAddress(module_, "asan_HeapFree"));
137 E : ASSERT_TRUE(heap_free_ != nullptr);
138 E : }
139 :
140 E : void UnloadDll() {
141 E : if (module_ != NULL) {
142 E : ASSERT_TRUE(::FreeLibrary(module_));
143 E : module_ = nullptr;
144 E : heap_create_ = nullptr;
145 E : heap_destroy_ = nullptr;
146 E : heap_alloc_ = nullptr;
147 E : heap_free_ = nullptr;
148 : }
149 E : }
150 :
151 E : void ExpectedRecordsSeenTest(bool emit_stack_traces) {
152 E : scoped_ptr<base::Environment> env(base::Environment::Create());
153 E : DCHECK_NE(static_cast<base::Environment*>(nullptr), env.get());
154 E : if (emit_stack_traces) {
155 : env->SetVar(kParametersEnvVar,
156 E : "--stack-trace-tracking=emit --serialize-timestamps");
157 E : } else {
158 E : env->SetVar(kParametersEnvVar, "--stack-trace-tracking=none");
159 : }
160 :
161 E : ASSERT_NO_FATAL_FAILURE(StartService());
162 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
163 :
164 E : DWORD process_id = ::GetCurrentProcessId();
165 E : DWORD thread_id = ::GetCurrentThreadId();
166 :
167 : // Make some calls to the instrumented heap API.
168 E : HANDLE heap = (*heap_create_)(0, 0, 0);
169 E : ASSERT_TRUE(heap != nullptr);
170 E : void* alloc = (*heap_alloc_)(heap, 0, 1024);
171 E : ASSERT_TRUE(alloc != nullptr);
172 E : (*heap_free_)(heap, 0, alloc);
173 : // Deliberately keep around the value of |alloc| for checking expectation,
174 : // even though the memory it points to is no longer valid.
175 E : (*heap_destroy_)(heap);
176 : // Ditto for the value of |heap|.
177 :
178 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
179 E : ASSERT_NO_FATAL_FAILURE(StopService());
180 :
181 E : env->UnSetVar(kParametersEnvVar);
182 :
183 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
184 : EXPECT_CALL(handler_, OnProcessAttach(_, process_id, _, _))
185 E : .Times(testing::AnyNumber());
186 :
187 E : EXPECT_CALL(handler_,
188 : OnFunctionNameTableEntry(_, process_id, _)).Times(4);
189 E : EXPECT_CALL(handler_,
190 : OnDetailedFunctionCall(_, process_id, thread_id, _)).Times(4);
191 :
192 E : if (emit_stack_traces) {
193 E : EXPECT_CALL(handler_,
194 : OnStackTrace(_, process_id, _)).Times(4);
195 : }
196 :
197 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
198 :
199 : // Replay the log.
200 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs());
201 E : }
202 :
203 : protected:
204 : // The directory where trace file output will be written.
205 : base::ScopedTempDir temp_dir_;
206 :
207 : // The handler to which the trace file parser will delegate events.
208 : StrictMockParseEventHandler handler_;
209 :
210 : // Functions exported from the memory profiler client dll.
211 : HeapCreatePtr heap_create_;
212 : HeapDestroyPtr heap_destroy_;
213 : HeapAllocPtr heap_alloc_;
214 : HeapFreePtr heap_free_;
215 :
216 : // Our call trace service process instance.
217 : testing::CallTraceService service_;
218 :
219 : private:
220 : HMODULE module_;
221 : };
222 :
223 : } // namespace
224 :
225 E : TEST_F(MemoryProfilerTest, NoServerNoCrash) {
226 E : ASSERT_NO_FATAL_FAILURE(LoadDll());
227 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
228 E : }
229 :
230 E : TEST_F(MemoryProfilerTest, ExpectedRecordsSeenTestNoStackTraces) {
231 E : ASSERT_NO_FATAL_FAILURE(ExpectedRecordsSeenTest(false));
232 E : }
233 :
234 E : TEST_F(MemoryProfilerTest, ExpectedRecordsSeenTestWithStackTraces) {
235 E : ASSERT_NO_FATAL_FAILURE(ExpectedRecordsSeenTest(true));
236 E : }
237 :
238 : } // namespace memprof
239 : } // namespace agent
|