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 : #include "base/environment.h"
16 : #include "base/files/file_enumerator.h"
17 : #include "base/files/file_path.h"
18 : #include "base/process/kill.h"
19 : #include "base/strings/string_util.h"
20 : #include "base/strings/stringprintf.h"
21 : #include "base/strings/utf_string_conversions.h"
22 : #include "base/win/pe_image.h"
23 : #include "base/win/scoped_com_initializer.h"
24 : #include "gmock/gmock.h"
25 : #include "gtest/gtest.h"
26 : #include "pcrecpp.h" // NOLINT
27 : #include "syzygy/agent/asan/rtl_impl.h"
28 : #include "syzygy/agent/asan/runtime.h"
29 : #include "syzygy/block_graph/transforms/chained_basic_block_transforms.h"
30 : #include "syzygy/common/asan_parameters.h"
31 : #include "syzygy/common/indexed_frequency_data.h"
32 : #include "syzygy/common/unittest_util.h"
33 : #include "syzygy/core/disassembler_util.h"
34 : #include "syzygy/core/unittest_util.h"
35 : #include "syzygy/grinder/basic_block_util.h"
36 : #include "syzygy/grinder/grinder.h"
37 : #include "syzygy/grinder/grinders/coverage_grinder.h"
38 : #include "syzygy/grinder/grinders/indexed_frequency_data_grinder.h"
39 : #include "syzygy/grinder/grinders/profile_grinder.h"
40 : #include "syzygy/instrument/instrument_app.h"
41 : #include "syzygy/instrument/transforms/asan_transform.h"
42 : #include "syzygy/integration_tests/asan_page_protection_tests.h"
43 : #include "syzygy/integration_tests/integration_tests_dll.h"
44 : #include "syzygy/pe/decomposer.h"
45 : #include "syzygy/pe/pe_transform_policy.h"
46 : #include "syzygy/pe/unittest_util.h"
47 : #include "syzygy/poirot/minidump_processor.h"
48 : #include "syzygy/testing/laa.h"
49 : #include "syzygy/trace/agent_logger/agent_logger.h"
50 : #include "syzygy/trace/common/unittest_util.h"
51 :
52 : namespace integration_tests {
53 :
54 : namespace {
55 :
56 : // The exit code used by report_crash_with_protobuf_harness if the
57 : // exception was appropriately dispatched but did not contain a valid protobuf.
58 : const int kExeReportCrashWithProtobufExitCodeBadProtobuf = 97;
59 :
60 : // The exit code used by report_crash_with_protobuf_harness if the
61 : // exception was appropriately dispatched and contained a valid protobuf.
62 : const int kExeReportCrashWithProtobufExitCode = 98;
63 :
64 : // The exit code used by crash_for_exception_harness if the exception
65 : // was appropriately dispatched.
66 : const int kExeCrashForExceptionExitCode = 99;
67 :
68 : using grinder::basic_block_util::IndexedFrequencyInformation;
69 : using grinder::basic_block_util::IndexedFrequencyMap;
70 : using grinder::basic_block_util::ModuleIndexedFrequencyMap;
71 : using instrument::InstrumentApp;
72 : using trace::parser::Parser;
73 : typedef block_graph::BlockGraph::Block Block;
74 : typedef block_graph::BlockGraph::BlockMap BlockMap;
75 : typedef application::Application<InstrumentApp> TestApp;
76 : typedef grinder::CoverageData::LineExecutionCountMap LineExecutionCountMap;
77 : typedef grinder::CoverageData::SourceFileCoverageData SourceFileCoverageData;
78 : typedef grinder::CoverageData::SourceFileCoverageDataMap
79 : SourceFileCoverageDataMap;
80 :
81 : #define _STRINGIFY(s) #s
82 : #define STRINGIFY(s) _STRINGIFY(s)
83 :
84 : const char kAsanAccessViolationLog[] =
85 : "SyzyASAN: Caught an invalid access via an access violation exception.";
86 : const char kAsanHandlingException[] = "SyzyASAN: Handling an exception.";
87 : const char kAsanHeapBufferOverflow[] = "SyzyASAN error: heap-buffer-overflow ";
88 : const char kAsanCorruptHeap[] = "SyzyASAN error: corrupt-heap ";
89 : const char kAsanHeapUseAfterFree[] = "SyzyASAN error: heap-use-after-free ";
90 : const char kAsanNearNullptrAccessHeapCorruption[] =
91 : "SyzyASAN: Caught a near-nullptr access with heap corruption.";
92 : const char kAsanNearNullptrAccessNoHeapCorruption[] =
93 : "SyzyASAN: Ignoring a near-nullptr access without heap corruption.";
94 :
95 : // A convenience class for controlling an out of process agent_logger instance,
96 : // and getting the contents of its log file. Not thread safe.
97 : struct ScopedAgentLogger {
98 E : explicit ScopedAgentLogger(base::FilePath temp_dir)
99 E : : nul_(NULL), temp_dir_(temp_dir) {
100 E : agent_logger_ = testing::GetOutputRelativePath(
101 : L"agent_logger.exe");
102 E : instance_id_ = base::StringPrintf("integra%08X", ::GetCurrentProcessId());
103 E : }
104 :
105 E : ~ScopedAgentLogger() {
106 : // Clean up the temp directory if we created one.
107 E : if (!temp_dir_.empty())
108 E : base::DeleteFile(temp_dir_, true);
109 :
110 E : if (nul_) {
111 E : ::CloseHandle(nul_);
112 E : nul_ = NULL;
113 : }
114 E : }
115 :
116 E : void RunAction(const char* action, base::Process* process) {
117 E : DCHECK_NE(static_cast<const char*>(nullptr), action);
118 E : DCHECK_NE(static_cast<base::Process*>(nullptr), process);
119 :
120 E : base::CommandLine cmd_line(agent_logger_);
121 E : cmd_line.AppendSwitchASCII("instance-id", instance_id_);
122 E : cmd_line.AppendSwitchPath("minidump-dir", temp_dir_);
123 E : cmd_line.AppendSwitchPath("output-file", log_file_);
124 E : cmd_line.AppendArg(action);
125 E : base::LaunchOptions options;
126 E : options.inherit_handles = true;
127 E : options.stderr_handle = nul_;
128 E : options.stdin_handle = nul_;
129 E : options.stdout_handle = nul_;
130 E : *process = base::LaunchProcess(cmd_line, options);
131 E : DCHECK(process->IsValid());
132 E : }
133 :
134 E : void Start() {
135 E : DCHECK(!process_.IsValid());
136 :
137 E : if (nul_ == NULL) {
138 E : nul_ = CreateFile(L"NUL", GENERIC_READ | GENERIC_WRITE, 0, NULL,
139 : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
140 E : CHECK(nul_);
141 : }
142 :
143 E : log_file_ = temp_dir_.Append(L"integration_test.log");
144 :
145 E : std::wstring start_event_name(L"syzygy-logger-started-");
146 E : start_event_name += base::ASCIIToUTF16(instance_id_);
147 E : base::win::ScopedHandle start_event(
148 : ::CreateEvent(NULL, FALSE, FALSE, start_event_name.c_str()));
149 :
150 E : RunAction("start", &process_);
151 :
152 E : ::WaitForSingleObject(start_event.Get(), INFINITE);
153 E : }
154 :
155 E : void Stop() {
156 E : DCHECK(process_.IsValid());
157 :
158 E : base::Process process;
159 E : RunAction("stop", &process);
160 E : int exit_code = 0;
161 E : CHECK(process.WaitForExit(&exit_code));
162 E : CHECK(process_.WaitForExit(&exit_code));
163 :
164 : // Read the contents of the log file.
165 E : if (base::PathExists(log_file_))
166 E : CHECK(base::ReadFileToString(log_file_, &log_contents_));
167 E : }
168 :
169 E : void GetLog(std::string* log) {
170 E : DCHECK_NE(static_cast<std::string*>(nullptr), log);
171 E : *log = log_contents_;
172 E : }
173 :
174 : // Initialized at construction.
175 : base::FilePath agent_logger_;
176 : std::string instance_id_;
177 :
178 : // Modified by Start and Stop.
179 : base::FilePath temp_dir_;
180 : base::FilePath log_file_;
181 : base::Process process_;
182 : HANDLE nul_;
183 :
184 : // Modified by Stop.
185 : std::string log_contents_;
186 : };
187 :
188 : enum AccessMode {
189 : ASAN_READ_ACCESS = agent::asan::ASAN_READ_ACCESS,
190 : ASAN_WRITE_ACCESS = agent::asan::ASAN_WRITE_ACCESS,
191 : ASAN_UNKNOWN_ACCESS = agent::asan::ASAN_UNKNOWN_ACCESS,
192 : };
193 :
194 : enum BadAccessKind {
195 : UNKNOWN_BAD_ACCESS = agent::asan::UNKNOWN_BAD_ACCESS,
196 : USE_AFTER_FREE = agent::asan::USE_AFTER_FREE,
197 : HEAP_BUFFER_OVERFLOW = agent::asan::HEAP_BUFFER_OVERFLOW,
198 : HEAP_BUFFER_UNDERFLOW = agent::asan::HEAP_BUFFER_UNDERFLOW,
199 : CORRUPT_BLOCK = agent::asan::CORRUPT_BLOCK,
200 : CORRUPT_HEAP = agent::asan::CORRUPT_HEAP,
201 : };
202 :
203 : // Contains the number of Asan errors reported with our callback.
204 : int asan_error_count;
205 : // Contains the last Asan error reported.
206 : agent::asan::AsanErrorInfo last_asan_error;
207 :
208 E : void AsanCallback(agent::asan::AsanErrorInfo* info) {
209 E : asan_error_count++;
210 E : last_asan_error = *info;
211 : // We want to prevent write errors from corrupting the underlying block hence
212 : // we stop the flow of execution by raising an exception. The faulty calls are
213 : // themselves wrapped in try/catch statements, and continue executing
214 : // afterwards. Thus, they clean up after themselves.
215 : //
216 : // In the case of block corruption we elect to allow the code to continue
217 : // executing so that the normal code path is taken. If we raise an exception
218 : // this actually prevents the AsanHeap cleanup code from continuing, and we
219 : // leak memory.
220 E : if (info->error_type != CORRUPT_BLOCK)
221 E : ::RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, NULL);
222 E : }
223 :
224 E : void ResetAsanErrors() {
225 E : asan_error_count = 0;
226 E : }
227 :
228 E : HMODULE GetAsanModule() {
229 E : HMODULE asan_module = GetModuleHandle(L"syzyasan_rtl.dll");
230 E : return asan_module;
231 E : }
232 :
233 E : void SetAsanDefaultCallBack(AsanErrorCallBack callback) {
234 : typedef void (WINAPI *AsanSetCallBack)(AsanErrorCallBack);
235 :
236 E : HMODULE asan_module = GetAsanModule();
237 E : DCHECK(asan_module != NULL);
238 : AsanSetCallBack set_callback = reinterpret_cast<AsanSetCallBack>(
239 E : ::GetProcAddress(asan_module, "asan_SetCallBack"));
240 E : DCHECK(set_callback != NULL);
241 :
242 E : set_callback(callback);
243 E : }
244 :
245 E : agent::asan::OnExceptionCallback on_exception_callback;
246 :
247 i : void DispatchOnExceptionCallback(EXCEPTION_POINTERS* e) {
248 i : if (!on_exception_callback.is_null())
249 i : on_exception_callback.Run(e);
250 i : }
251 :
252 E : void SetOnExceptionCallback(agent::asan::OnExceptionCallback callback) {
253 : typedef void (*OnExceptionCallback)(EXCEPTION_POINTERS*);
254 : typedef void (WINAPI *SetOnExceptionCallback)(OnExceptionCallback);
255 :
256 E : HMODULE asan_module = GetAsanModule();
257 E : DCHECK(asan_module != NULL);
258 : SetOnExceptionCallback set_callback =
259 : reinterpret_cast<SetOnExceptionCallback>(
260 E : ::GetProcAddress(asan_module, "asan_SetOnExceptionCallback"));
261 E : DCHECK(set_callback != NULL);
262 :
263 E : if (callback.is_null()) {
264 i : set_callback(nullptr);
265 i : on_exception_callback.Reset();
266 i : } else {
267 E : set_callback(&DispatchOnExceptionCallback);
268 E : on_exception_callback = callback;
269 : }
270 E : }
271 :
272 E : agent::asan::AsanRuntime* GetActiveAsanRuntime() {
273 E : HMODULE asan_module = GetAsanModule();
274 E : DCHECK(asan_module != NULL);
275 :
276 : typedef agent::asan::AsanRuntime* (WINAPI *AsanGetActiveRuntimePtr)();
277 : AsanGetActiveRuntimePtr asan_get_active_runtime =
278 : reinterpret_cast<AsanGetActiveRuntimePtr>(
279 E : ::GetProcAddress(asan_module, "asan_GetActiveRuntime"));
280 E : DCHECK_NE(reinterpret_cast<AsanGetActiveRuntimePtr>(NULL),
281 E : asan_get_active_runtime);
282 :
283 E : return (*asan_get_active_runtime)();
284 E : }
285 :
286 : // Filters non-continuable exceptions in the given module.
287 : int FilterExceptionsInModule(HMODULE module,
288 : unsigned int code,
289 E : struct _EXCEPTION_POINTERS* ep) {
290 : // Do a basic sanity check on the input parameters.
291 : if (module == NULL ||
292 : code != EXCEPTION_NONCONTINUABLE_EXCEPTION ||
293 : ep == NULL ||
294 E : ep->ContextRecord == NULL ||
295 : ep->ExceptionRecord == NULL) {
296 i : return EXCEPTION_CONTINUE_SEARCH;
297 : }
298 :
299 : // Get the module extents in memory.
300 E : base::win::PEImage image(module);
301 E : uint8_t* module_start = reinterpret_cast<uint8_t*>(module);
302 : uint8_t* module_end =
303 E : module_start + image.GetNTHeaders()->OptionalHeader.SizeOfImage;
304 :
305 : // Filter exceptions where the return address originates from within the
306 : // instrumented module.
307 E : uint8_t** ebp = reinterpret_cast<uint8_t**>(ep->ContextRecord->Ebp);
308 E : uint8_t* ret = ebp[1];
309 E : if (ret >= module_start && ret < module_end)
310 E : return EXCEPTION_EXECUTE_HANDLER;
311 :
312 i : return EXCEPTION_CONTINUE_SEARCH;
313 E : }
314 :
315 : typedef std::map<std::string, FARPROC> ImportMap;
316 : bool OnImport(const base::win::PEImage& image,
317 : LPCSTR module,
318 : DWORD ordinal,
319 : LPCSTR name,
320 : DWORD hint,
321 : PIMAGE_THUNK_DATA iat,
322 E : PVOID cookie) {
323 E : if (name == nullptr) {
324 : // This is an ordinal import.
325 E : return true;
326 : }
327 :
328 E : ImportMap* imports = reinterpret_cast<ImportMap*>(cookie);
329 E : imports->insert(
330 : std::make_pair(name, reinterpret_cast<FARPROC>(iat->u1.Function)));
331 E : return true;
332 E : }
333 :
334 E : bool GetModuleNamedImports(HMODULE module, ImportMap* imports) {
335 E : base::win::PEImage image(module);
336 E : if (!image.VerifyMagic())
337 i : return false;
338 :
339 E : return image.EnumAllImports(OnImport, imports);
340 E : }
341 :
342 : class TestingProfileGrinder : public grinder::grinders::ProfileGrinder {
343 : public:
344 : // Expose for testing.
345 : typedef grinder::grinders::ProfileGrinder::InvocationNodeMap
346 : InvocationNodeMap;
347 : typedef grinder::grinders::ProfileGrinder::ModuleInformationSet
348 : ModuleInformationSet;
349 :
350 : using grinder::grinders::ProfileGrinder::PartData;
351 : using grinder::grinders::ProfileGrinder::PartDataMap;
352 : using grinder::grinders::ProfileGrinder::PartKey;
353 :
354 : using grinder::grinders::ProfileGrinder::modules_;
355 : using grinder::grinders::ProfileGrinder::parts_;
356 : };
357 :
358 : class LenientInstrumentAppIntegrationTest : public testing::PELibUnitTest {
359 : public:
360 : typedef testing::PELibUnitTest Super;
361 :
362 : // A callback that gets hooked up to catch exceptions in the RTL.
363 i : MOCK_METHOD1(OnExceptionCallback, void(EXCEPTION_POINTERS*));
364 :
365 : LenientInstrumentAppIntegrationTest()
366 E : : cmd_line_(base::FilePath(L"instrument.exe")),
367 E : test_impl_(test_app_.implementation()),
368 E : image_layout_(&block_graph_),
369 E : get_my_rva_(NULL) {
370 E : }
371 :
372 E : void SetUp() {
373 E : Super::SetUp();
374 :
375 : // Several of the tests generate progress and (deliberate) error messages
376 : // that would otherwise clutter the unittest output.
377 E : logging::SetMinLogLevel(logging::LOG_FATAL);
378 :
379 : // Setup the IO streams.
380 E : this->CreateTemporaryDir(&temp_dir_);
381 E : stdin_path_ = temp_dir_.Append(L"NUL");
382 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
383 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
384 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
385 :
386 : // Initialize the (potential) input and output path values.
387 : base::FilePath abs_input_dll_path_ =
388 E : testing::GetExeRelativePath(testing::kIntegrationTestsDllName);
389 E : input_dll_path_ = testing::GetRelativePath(abs_input_dll_path_);
390 E : output_dll_path_ = temp_dir_.Append(input_dll_path_.BaseName());
391 :
392 : // Initialize call_service output directory for produced trace files.
393 E : traces_dir_ = temp_dir_.Append(L"traces");
394 :
395 : // Initialize call_service session id.
396 E : service_.SetEnvironment();
397 :
398 E : ASSERT_NO_FATAL_FAILURE(ConfigureTestApp(&test_app_));
399 E : }
400 :
401 E : void TearDown() {
402 : // We need to release the module handle before Super::TearDown, otherwise
403 : // the library file cannot be deleted.
404 E : module_.Release();
405 E : Super::TearDown();
406 E : }
407 :
408 : // Points the application at the fixture's command-line and IO streams.
409 : template<typename TestAppType>
410 E : void ConfigureTestApp(TestAppType* test_app) {
411 E : test_app->set_command_line(&cmd_line_);
412 E : test_app->set_in(in());
413 E : test_app->set_out(out());
414 E : test_app->set_err(err());
415 E : }
416 :
417 E : void StartService() {
418 E : service_.Start(traces_dir_);
419 E : }
420 :
421 E : void StopService() {
422 E : service_.Stop();
423 E : }
424 :
425 E : void UnloadDll() {
426 E : module_.Reset(NULL);
427 E : }
428 :
429 : // Runs an instrumentation pass in the given mode and validates that the
430 : // resulting output DLL loads.
431 E : void EndToEndTest(const std::string& mode) {
432 E : cmd_line_.AppendSwitchPath("input-image", input_dll_path_);
433 E : cmd_line_.AppendSwitchPath("output-image", output_dll_path_);
434 E : cmd_line_.AppendSwitchASCII("mode", mode);
435 :
436 : // Create the instrumented DLL.
437 E : application::Application<instrument::InstrumentApp> app;
438 E : ASSERT_NO_FATAL_FAILURE(ConfigureTestApp(&app));
439 E : ASSERT_EQ(0, app.Run());
440 :
441 : // Validate that the test dll loads post instrumentation.
442 E : ASSERT_NO_FATAL_FAILURE(LoadTestDll(output_dll_path_, &module_));
443 E : }
444 :
445 : // Invoke a test function inside test_dll by addressing it with a test id.
446 : // Returns the value resulting from the test function execution.
447 E : unsigned int InvokeTestDllFunction(testing::EndToEndTestId test) {
448 : // Load the exported 'function_name' function.
449 : typedef unsigned int (CALLBACK* TestDllFuncs)(unsigned int);
450 : TestDllFuncs func = reinterpret_cast<TestDllFuncs>(
451 E : ::GetProcAddress(module_, "EndToEndTest"));
452 E : DCHECK(func != NULL);
453 :
454 : // Invoke it, and returns its value.
455 E : return func(test);
456 E : }
457 :
458 : int RunOutOfProcessFunction(const base::string16& harness_name,
459 : testing::EndToEndTestId test,
460 E : bool expect_exception) {
461 E : base::FilePath harness = testing::GetExeRelativePath(harness_name.c_str());
462 E : base::CommandLine cmd_line(harness);
463 E : cmd_line.AppendSwitchASCII("test", base::StringPrintf("%d", test));
464 E : cmd_line.AppendSwitchPath("dll", output_dll_path_);
465 E : if (expect_exception)
466 E : cmd_line.AppendSwitch("expect-exception");
467 :
468 E : base::LaunchOptions options;
469 E : base::Process process = base::LaunchProcess(cmd_line, options);
470 E : EXPECT_TRUE(process.IsValid());
471 :
472 E : int exit_code = 0;
473 E : EXPECT_TRUE(process.WaitForExit(&exit_code));
474 E : return exit_code;
475 E : }
476 :
477 : // Runs an asan error check in an external process, invoking the test via the
478 : // integration test harness.
479 : void OutOfProcessAsanErrorCheck(testing::EndToEndTestId test,
480 : bool expect_exception,
481 E : std::string* log) {
482 E : DCHECK_NE(static_cast<std::string*>(nullptr), log);
483 :
484 : // If running under the debugger then don't do this test. The debugger's
485 : // exception handler prevents this from completing as expected.
486 E : if (expect_exception && ::IsDebuggerPresent())
487 i : return;
488 :
489 E : ScopedAgentLogger logger(temp_dir_);
490 E : logger.Start();
491 :
492 E : std::unique_ptr<base::Environment> env(base::Environment::Create());
493 E : CHECK_NE(static_cast<base::Environment*>(nullptr), env.get());
494 :
495 : // Update the instance ID environment variable to specifically aim the
496 : // Asan RTL to the agent logger we are running. We have to be careful not
497 : // to influence other RPC settings so as not to break coverage support.
498 E : base::FilePath agent = testing::GetExeRelativePath(L"syzyasan_rtl.dll");
499 E : std::string instance_id = base::WideToUTF8(agent.value());
500 E : instance_id.append(",");
501 E : instance_id.append(logger.instance_id_);
502 E : bool had_instance_id = false;
503 E : std::string orig_instance_id;
504 E : had_instance_id = env->GetVar(kSyzygyRpcInstanceIdEnvVar,
505 : &orig_instance_id);
506 E : if (had_instance_id) {
507 E : instance_id.append(";");
508 E : instance_id.append(orig_instance_id);
509 : }
510 E : env->SetVar(kSyzygyRpcInstanceIdEnvVar, instance_id);
511 :
512 E : int exit_code = RunOutOfProcessFunction(L"integration_tests_harness.exe",
513 : test, expect_exception);
514 E : EXPECT_EQ(0, exit_code);
515 E : logger.Stop();
516 :
517 : // Restore the instance ID variable to its original state.
518 E : if (had_instance_id) {
519 E : env->SetVar(kSyzygyRpcInstanceIdEnvVar, orig_instance_id);
520 E : } else {
521 i : env->UnSetVar(kSyzygyRpcInstanceIdEnvVar);
522 : }
523 :
524 E : logger.GetLog(log);
525 E : }
526 :
527 : void OutOfProcessAsanErrorCheckAndValidateLog(
528 : testing::EndToEndTestId test,
529 : bool expect_exception,
530 : const base::StringPiece& log_message_1,
531 E : const base::StringPiece& log_message_2) {
532 : // If running under the debugger then don't do this test. The debugger's
533 : // exception handler prevents this from completing as expected.
534 E : if (expect_exception && ::IsDebuggerPresent())
535 i : return;
536 :
537 E : std::string log;
538 E : OutOfProcessAsanErrorCheck(test, expect_exception, &log);
539 :
540 E : if (!expect_exception)
541 E : return;
542 : // Check the log for any messages that are expected.
543 E : if (!log_message_1.empty()) {
544 E : EXPECT_NE(std::string::npos, log.find(log_message_1.as_string()))
545 : << "Expected to find '" << log_message_1 << "' in logs: " << log;
546 : }
547 E : if (!log_message_2.empty()) {
548 E : EXPECT_NE(std::string::npos, log.find(log_message_2.as_string()))
549 : << "Expected to find '" << log_message_2 << "' in logs: " << log;
550 : }
551 E : }
552 :
553 E : void CheckTestDllImportsRedirected() {
554 E : HMODULE rtl = GetAsanModule();
555 E : ASSERT_NE(static_cast<HMODULE>(nullptr), rtl);
556 :
557 E : ImportMap imports;
558 E : ASSERT_TRUE(GetModuleNamedImports(module_, &imports));
559 E : for (auto pair : imports) {
560 E : const std::string& name = pair.first;
561 E : const FARPROC imported_fn = pair.second;
562 :
563 : // Is this an instrumentation import?
564 : const bool is_asan_fn =
565 E : base::StartsWith(name, "asan_", base::CompareCase::SENSITIVE);
566 E : if (!is_asan_fn)
567 E : continue;
568 :
569 : // Retrieve the corresponding export on the instrumentation DLL.
570 E : FARPROC rtl_export_fn = ::GetProcAddress(rtl, name.c_str());
571 :
572 : // Is it a memory accessor?
573 : const bool is_asan_check_fn =
574 E : base::StartsWith(name, "asan_check", base::CompareCase::SENSITIVE);
575 E : if (is_asan_check_fn) {
576 : // Memory acessors in the dynamic RTL must be redirected after first
577 : // use of the function. If the dynamic RTL doesn't redirect the imports
578 : // everything will still work, just terribly slowly.
579 E : ASSERT_NE(rtl_export_fn, imported_fn);
580 E : } else {
581 E : ASSERT_EQ(rtl_export_fn, imported_fn);
582 : }
583 E : }
584 E : }
585 :
586 E : void EndToEndCheckTestDll() {
587 : // Validate that behavior is unchanged after instrumentation.
588 E : EXPECT_EQ(0xfff80200, InvokeTestDllFunction(testing::kArrayComputation1));
589 E : EXPECT_EQ(0x00000200, InvokeTestDllFunction(testing::kArrayComputation2));
590 E : }
591 :
592 : bool AsanErrorCheck(testing::EndToEndTestId test,
593 : BadAccessKind kind,
594 : AccessMode mode,
595 : size_t size,
596 : size_t max_tries,
597 E : bool unload) {
598 : // A small selection of tests can fail due to hash collisions. These are
599 : // run repeatedly and expected to pass at least once. Every other test is
600 : // run with max_tries == 1.
601 E : if (max_tries != 1) {
602 : // Ensure that only the desired tests are being run with retries. This is
603 : // a second layer of safety to make sure that flaky tests aren't simply
604 : // being hidden.
605 E : EXPECT_TRUE(test == testing::kAsanCorruptBlock ||
606 : test == testing::kAsanCorruptBlockInQuarantine);
607 : }
608 :
609 E : ResetAsanErrors();
610 E : EXPECT_NO_FATAL_FAILURE(SetAsanDefaultCallBack(AsanCallback));
611 :
612 : // Hook up the OnException callback to the test fixture.
613 E : SetOnExceptionCallback(base::Bind(
614 : &LenientInstrumentAppIntegrationTest::OnExceptionCallback,
615 : base::Unretained(this)));
616 :
617 E : for (size_t i = 0; i < max_tries; ++i) {
618 E : InvokeTestDllFunction(test);
619 E : if (unload)
620 E : UnloadDll();
621 :
622 : // If this appears to have failed then retry it for all but the last
623 : // attempt. Some tests have a non-zero chance of failure, but their
624 : // chances of failing repeatedly are infinitesimally small.
625 E : if (asan_error_count == 0 && i + 1 < max_tries) {
626 : // If the module was unloaded and the test is retrying, then reload it.
627 i : if (unload)
628 i : EXPECT_NO_FATAL_FAILURE(LoadTestDll(output_dll_path_, &module_));
629 i : continue;
630 : }
631 :
632 : if (asan_error_count == 0 ||
633 : last_asan_error.error_type != kind ||
634 E : last_asan_error.access_mode != mode ||
635 : last_asan_error.access_size != size) {
636 i : return false;
637 : }
638 E : break;
639 i : }
640 :
641 : // Clear any expectations on this fixture.
642 E : testing::Mock::VerifyAndClearExpectations(this);
643 :
644 E : return true;
645 E : }
646 :
647 : bool FilteredAsanErrorCheck(testing::EndToEndTestId test,
648 : BadAccessKind kind,
649 : AccessMode mode,
650 : size_t size,
651 : size_t max_tries,
652 i : bool unload) {
653 i : __try {
654 i : return AsanErrorCheck(test, kind, mode, size, max_tries, unload);
655 i : } __except (FilterExceptionsInModule(module_, // NOLINT
656 : GetExceptionCode(),
657 : GetExceptionInformation())) {
658 : // If the exception is of the expected type and originates from the
659 : // instrumented module, then we indicate that no Asan error was
660 : // detected.
661 i : return false;
662 : }
663 i : }
664 :
665 E : void AsanErrorCheckTestDll() {
666 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead8BufferOverflow,
667 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
668 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead16BufferOverflow,
669 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 2, 1, false));
670 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead32BufferOverflow,
671 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 4, 1, false));
672 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead64BufferOverflow,
673 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 8, 1, false));
674 :
675 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead8BufferUnderflow,
676 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
677 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead16BufferUnderflow,
678 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 2, 1, false));
679 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead32BufferUnderflow,
680 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 4, 1, false));
681 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead64BufferUnderflow,
682 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 8, 1, false));
683 :
684 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite8BufferOverflow,
685 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
686 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite16BufferOverflow,
687 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 2, 1, false));
688 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite32BufferOverflow,
689 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 4, 1, false));
690 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite64BufferOverflow,
691 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 8, 1, false));
692 :
693 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite8BufferUnderflow,
694 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
695 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite16BufferUnderflow,
696 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 2, 1, false));
697 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite32BufferUnderflow,
698 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 4, 1, false));
699 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite64BufferUnderflow,
700 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 8, 1, false));
701 :
702 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead8UseAfterFree,
703 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
704 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead16UseAfterFree,
705 : USE_AFTER_FREE, ASAN_READ_ACCESS, 2, 1, false));
706 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead32UseAfterFree,
707 : USE_AFTER_FREE, ASAN_READ_ACCESS, 4, 1, false));
708 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanRead64UseAfterFree,
709 : USE_AFTER_FREE, ASAN_READ_ACCESS, 8, 1, false));
710 :
711 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite8UseAfterFree,
712 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 1, 1, false));
713 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite16UseAfterFree,
714 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 2, 1, false));
715 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite32UseAfterFree,
716 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 4, 1, false));
717 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWrite64UseAfterFree,
718 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 8, 1, false));
719 E : }
720 :
721 E : void AsanErrorCheckSampledAllocations() {
722 : // This assumes we have a 50% allocation sampling rate.
723 :
724 : // Run Asan tests over and over again until we've done enough of them. We
725 : // only check the read operations as the writes may actually cause
726 : // corruption if not caught.
727 E : size_t good = 0;
728 E : size_t test = 0;
729 E : while (test < 1000) {
730 E : good += FilteredAsanErrorCheck(testing::kAsanRead8BufferOverflow,
731 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false) ? 1 : 0;
732 E : good += FilteredAsanErrorCheck(testing::kAsanRead16BufferOverflow,
733 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 2, 1, false) ? 1 : 0;
734 E : good += FilteredAsanErrorCheck(testing::kAsanRead32BufferOverflow,
735 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 4, 1, false) ? 1 : 0;
736 E : good += FilteredAsanErrorCheck(testing::kAsanRead64BufferOverflow,
737 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 8, 1, false) ? 1 : 0;
738 E : test += 4;
739 :
740 E : good += FilteredAsanErrorCheck(testing::kAsanRead8BufferUnderflow,
741 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false) ? 1 : 0;
742 E : good += FilteredAsanErrorCheck(testing::kAsanRead16BufferUnderflow,
743 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 2, 1, false) ? 1 : 0;
744 E : good += FilteredAsanErrorCheck(testing::kAsanRead32BufferUnderflow,
745 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 4, 1, false) ? 1 : 0;
746 E : good += FilteredAsanErrorCheck(testing::kAsanRead64BufferUnderflow,
747 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 8, 1, false) ? 1 : 0;
748 E : test += 4;
749 E : }
750 :
751 : // We expect half of the bugs to have been found, as the allocations are
752 : // subsampled. With 1000 allocations this gives us 10 nines of confidence
753 : // that the detection rate will be within 50 +/- 10%.
754 E : EXPECT_LE(4 * test / 10, good);
755 E : EXPECT_GE(6 * test / 10, good);
756 E : }
757 :
758 E : void AsanErrorCheckInterceptedFunctions() {
759 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemsetOverflow,
760 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
761 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemsetUnderflow,
762 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
763 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemsetUseAfterFree,
764 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 1, 1, false));
765 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemchrOverflow,
766 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
767 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemchrUnderflow,
768 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
769 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemchrUseAfterFree,
770 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
771 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemmoveReadOverflow,
772 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
773 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemmoveReadUnderflow,
774 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
775 : // In this test both buffers passed to memmove have been freed, but as the
776 : // interceptor starts by checking the source buffer this use after free is
777 : // seen as an invalid read access.
778 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemmoveUseAfterFree,
779 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
780 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemmoveWriteOverflow,
781 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
782 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemmoveWriteUnderflow,
783 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
784 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemcpyReadOverflow,
785 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
786 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemcpyReadUnderflow,
787 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
788 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemcpyUseAfterFree,
789 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
790 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemcpyWriteOverflow,
791 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
792 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanMemcpyWriteUnderflow,
793 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
794 :
795 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrlenOverflow,
796 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
797 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrlenUnderflow,
798 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
799 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrlenUseAfterFree,
800 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
801 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrnlenOverflow,
802 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
803 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrnlenUnderflow,
804 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
805 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrnlenUseAfterFree,
806 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
807 : // TODO(chrisha): These should actually be indicated as 2 byte reads. This
808 : // needs to be fixed in the runtime.
809 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsnlenOverflow,
810 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
811 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsnlenUnderflow,
812 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
813 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsnlenUseAfterFree,
814 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
815 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrrchrOverflow,
816 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
817 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrrchrUnderflow,
818 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
819 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrrchrUseAfterFree,
820 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
821 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsrchrOverflow,
822 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
823 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsrchrUnderflow,
824 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
825 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsrchrUseAfterFree,
826 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
827 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcschrOverflow,
828 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
829 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcschrUnderflow,
830 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
831 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcschrUseAfterFree,
832 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
833 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWcsstrKeysOverflow,
834 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
835 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpySrcOverflow,
836 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
837 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpySrcUnderflow,
838 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
839 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpySrcUseAfterFree,
840 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
841 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpyDstOverflow,
842 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
843 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpyDstUnderflow,
844 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
845 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncpyDstUseAfterFree,
846 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 1, 1, false));
847 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatSuffixOverflow,
848 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
849 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatSuffixUnderflow,
850 : HEAP_BUFFER_UNDERFLOW, ASAN_READ_ACCESS, 1, 1, false));
851 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatSuffixUseAfterFree,
852 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
853 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatDstOverflow,
854 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
855 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatDstUnderflow,
856 : HEAP_BUFFER_UNDERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
857 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanStrncatDstUseAfterFree,
858 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 1, 1, false));
859 :
860 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanReadFileOverflow,
861 : HEAP_BUFFER_OVERFLOW, ASAN_WRITE_ACCESS, 1, 1, false));
862 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanReadFileUseAfterFree,
863 : USE_AFTER_FREE, ASAN_WRITE_ACCESS, 1, 1, false));
864 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWriteFileOverflow,
865 : HEAP_BUFFER_OVERFLOW, ASAN_READ_ACCESS, 1, 1, false));
866 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanWriteFileUseAfterFree,
867 : USE_AFTER_FREE, ASAN_READ_ACCESS, 1, 1, false));
868 :
869 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanCorruptBlock,
870 : CORRUPT_BLOCK, ASAN_UNKNOWN_ACCESS, 0, 10, false));
871 :
872 : // We need to force the module to unload so that the quarantine gets
873 : // cleaned up and fires off the error we're looking for.
874 E : EXPECT_TRUE(AsanErrorCheck(testing::kAsanCorruptBlockInQuarantine,
875 : CORRUPT_BLOCK, ASAN_UNKNOWN_ACCESS, 0, 10, true));
876 :
877 E : OutOfProcessAsanErrorCheckAndValidateLog(
878 : testing::kAsanMemcmpAccessViolation, true, kAsanHandlingException,
879 : nullptr);
880 E : }
881 :
882 E : void AsanLargeBlockHeapTests(bool expect_exception) {
883 E : OutOfProcessAsanErrorCheckAndValidateLog(
884 : testing::kAsanReadLargeAllocationTrailerBeforeFree, expect_exception,
885 : kAsanAccessViolationLog, kAsanHeapBufferOverflow);
886 E : OutOfProcessAsanErrorCheckAndValidateLog(
887 : testing::kAsanReadLargeAllocationBodyAfterFree, true,
888 : kAsanAccessViolationLog, kAsanHeapUseAfterFree);
889 E : }
890 :
891 : void AsanZebraHeapTest(bool enabled);
892 :
893 E : void BBEntryInvokeTestDll() {
894 E : EXPECT_EQ(42, InvokeTestDllFunction(testing::kBBEntryCallOnce));
895 E : EXPECT_EQ(42, InvokeTestDllFunction(testing::kBBEntryCallTree));
896 E : EXPECT_EQ(42, InvokeTestDllFunction(testing::kBBEntryCallRecursive));
897 E : }
898 :
899 E : void ProfileInvokeTestDll() {
900 E : EXPECT_EQ(5, InvokeTestDllFunction(testing::kProfileCallExport));
901 : // Save the RVA of one of the invoked functions for testing later.
902 E : get_my_rva_ = InvokeTestDllFunction(testing::kProfileGetMyRVA);
903 :
904 : // The profiler will record the address of the first instruction of the
905 : // original function, which is six bytes past the start of the function
906 : // as seen by itself post-instrumentation.
907 E : get_my_rva_ += 6;
908 E : }
909 :
910 : uint32_t ProfileInvokeGetRVA() {
911 : return InvokeTestDllFunction(testing::kProfileGetMyRVA);
912 : }
913 :
914 E : void QueueTraces(Parser* parser) {
915 E : DCHECK(parser != NULL);
916 :
917 : // Queue up the trace file(s) we engendered.
918 E : base::FileEnumerator enumerator(traces_dir_,
919 : false,
920 : base::FileEnumerator::FILES);
921 E : while (true) {
922 E : base::FilePath trace_file = enumerator.Next();
923 E : if (trace_file.empty())
924 E : break;
925 E : ASSERT_TRUE(parser->OpenTraceFile(trace_file));
926 E : }
927 E : }
928 :
929 E : const Block* FindBlockWithName(std::string name) {
930 E : const BlockMap& blocks = block_graph_.blocks();
931 E : BlockMap::const_iterator block_iter = blocks.begin();
932 E : for (; block_iter != blocks.end(); ++block_iter) {
933 E : const Block& block = block_iter->second;
934 E : if (block.type() != block_graph::BlockGraph::CODE_BLOCK)
935 E : continue;
936 E : if (block.name().compare(name) == 0)
937 E : return █
938 E : }
939 i : return NULL;
940 E : }
941 :
942 : int GetBlockFrequency(const IndexedFrequencyMap& frequencies,
943 E : const Block* block) {
944 E : DCHECK(block != NULL);
945 : IndexedFrequencyMap::const_iterator entry =
946 E : frequencies.find(std::make_pair(block->addr(), 0));
947 E : if (entry == frequencies.end())
948 i : return 0;
949 E : return entry->second;
950 E : }
951 :
952 : void ExpectFunctionFrequency(const IndexedFrequencyMap& frequencies,
953 : const char* function_name,
954 E : int expected_frequency) {
955 E : DCHECK(function_name != NULL);
956 E : const Block* block = FindBlockWithName(function_name);
957 E : ASSERT_TRUE(block != NULL);
958 E : int exec_frequency = GetBlockFrequency(frequencies, block);
959 E : EXPECT_EQ(expected_frequency, exec_frequency);
960 E : }
961 :
962 E : void DecomposeImage() {
963 : // Decompose the DLL.
964 E : pe_image_.Init(input_dll_path_);
965 E : pe::Decomposer decomposer(pe_image_);
966 E : ASSERT_TRUE(decomposer.Decompose(&image_layout_));
967 E : }
968 :
969 E : void BBEntryCheckTestDll() {
970 E : Parser parser;
971 E : grinder::grinders::IndexedFrequencyDataGrinder grinder;
972 :
973 : // Initialize trace parser.
974 E : ASSERT_TRUE(parser.Init(&grinder));
975 E : grinder.SetParser(&parser);
976 :
977 : // Add generated traces to the parser.
978 E : QueueTraces(&parser);
979 :
980 : // Parse all traces.
981 E : ASSERT_TRUE(parser.Consume());
982 E : ASSERT_FALSE(parser.error_occurred());
983 E : ASSERT_TRUE(grinder.Grind());
984 :
985 : // Retrieve basic block count information.
986 E : const ModuleIndexedFrequencyMap& module_entry_count =
987 : grinder.frequency_data_map();
988 E : ASSERT_EQ(1u, module_entry_count.size());
989 :
990 : ModuleIndexedFrequencyMap::const_iterator entry_iter =
991 E : module_entry_count.begin();
992 E : const IndexedFrequencyInformation& info = entry_iter->second;
993 E : const IndexedFrequencyMap& entry_count = info.frequency_map;
994 :
995 : // Decompose the output image.
996 E : ASSERT_NO_FATAL_FAILURE(DecomposeImage());
997 :
998 : // Validate function entry counts.
999 E : ASSERT_NO_FATAL_FAILURE(
1000 : ExpectFunctionFrequency(entry_count, "BBEntryCallOnce", 1));
1001 E : ASSERT_NO_FATAL_FAILURE(
1002 : ExpectFunctionFrequency(entry_count, "BBEntryCallTree", 1));
1003 E : ASSERT_NO_FATAL_FAILURE(
1004 : ExpectFunctionFrequency(entry_count, "BBEntryFunction1", 4));
1005 E : ASSERT_NO_FATAL_FAILURE(
1006 : ExpectFunctionFrequency(entry_count, "BBEntryFunction2", 2));
1007 E : ASSERT_NO_FATAL_FAILURE(
1008 : ExpectFunctionFrequency(entry_count, "BBEntryFunction3", 1));
1009 E : ASSERT_NO_FATAL_FAILURE(
1010 : ExpectFunctionFrequency(entry_count, "BBEntryCallRecursive", 1));
1011 E : ASSERT_NO_FATAL_FAILURE(
1012 : ExpectFunctionFrequency(entry_count, "BBEntryFunctionRecursive", 42));
1013 E : }
1014 :
1015 E : void BranchCheckTestDll() {
1016 E : Parser parser;
1017 E : grinder::grinders::IndexedFrequencyDataGrinder grinder;
1018 :
1019 : // Initialize trace parser.
1020 E : ASSERT_TRUE(parser.Init(&grinder));
1021 E : grinder.SetParser(&parser);
1022 :
1023 : // Add generated traces to the parser.
1024 E : QueueTraces(&parser);
1025 :
1026 : // Parse all traces.
1027 E : ASSERT_TRUE(parser.Consume());
1028 E : ASSERT_FALSE(parser.error_occurred());
1029 E : ASSERT_TRUE(grinder.Grind());
1030 :
1031 : // Retrieve basic block count information.
1032 E : const grinder::basic_block_util::ModuleIndexedFrequencyMap& module_map =
1033 : grinder.frequency_data_map();
1034 E : ASSERT_EQ(1u, module_map.size());
1035 :
1036 E : ModuleIndexedFrequencyMap::const_iterator entry_iter = module_map.begin();
1037 E : const IndexedFrequencyInformation& information = entry_iter->second;
1038 E : const IndexedFrequencyMap& frequency_map = information.frequency_map;
1039 :
1040 : // Decompose the output image.
1041 E : ASSERT_NO_FATAL_FAILURE(DecomposeImage());
1042 :
1043 : // Validate function entry counts.
1044 E : ASSERT_NO_FATAL_FAILURE(
1045 : ExpectFunctionFrequency(frequency_map, "BBEntryCallOnce", 1));
1046 E : ASSERT_NO_FATAL_FAILURE(
1047 : ExpectFunctionFrequency(frequency_map, "BBEntryCallTree", 1));
1048 E : ASSERT_NO_FATAL_FAILURE(
1049 : ExpectFunctionFrequency(frequency_map, "BBEntryFunction1", 4));
1050 E : ASSERT_NO_FATAL_FAILURE(
1051 : ExpectFunctionFrequency(frequency_map, "BBEntryFunction2", 2));
1052 E : ASSERT_NO_FATAL_FAILURE(
1053 : ExpectFunctionFrequency(frequency_map, "BBEntryFunction3", 1));
1054 E : ASSERT_NO_FATAL_FAILURE(
1055 : ExpectFunctionFrequency(frequency_map, "BBEntryCallRecursive", 1));
1056 E : ASSERT_NO_FATAL_FAILURE(
1057 : ExpectFunctionFrequency(frequency_map, "BBEntryFunctionRecursive", 42));
1058 E : }
1059 :
1060 E : bool GetLineInfoExecution(const SourceFileCoverageData* data, size_t line) {
1061 E : DCHECK(data != NULL);
1062 :
1063 E : const LineExecutionCountMap& lines = data->line_execution_count_map;
1064 E : LineExecutionCountMap::const_iterator look = lines.find(line);
1065 E : if (look != lines.end()) {
1066 E : if (look->second != 0)
1067 E : return true;
1068 : }
1069 :
1070 E : return false;
1071 E : }
1072 :
1073 E : void CoverageInvokeTestDll() {
1074 E : EXPECT_EQ(182, InvokeTestDllFunction(testing::kCoverage1));
1075 E : EXPECT_EQ(182, InvokeTestDllFunction(testing::kCoverage2));
1076 E : EXPECT_EQ(2, InvokeTestDllFunction(testing::kCoverage3));
1077 E : }
1078 :
1079 E : void CoverageCheckTestDll() {
1080 E : Parser parser;
1081 E : grinder::grinders::CoverageGrinder grinder;
1082 :
1083 : // Initialize trace parser.
1084 E : ASSERT_TRUE(parser.Init(&grinder));
1085 E : grinder.SetParser(&parser);
1086 :
1087 : // Add generated traces to the parser.
1088 E : QueueTraces(&parser);
1089 :
1090 : // Parse all traces.
1091 E : ASSERT_TRUE(parser.Consume());
1092 E : ASSERT_FALSE(parser.error_occurred());
1093 E : ASSERT_TRUE(grinder.Grind());
1094 :
1095 : // Retrieve coverage information.
1096 E : const grinder::CoverageData& coverage_data = grinder.coverage_data();
1097 E : const SourceFileCoverageDataMap& files =
1098 : coverage_data.source_file_coverage_data_map();
1099 :
1100 : // Find file "coverage_tests.cc".
1101 E : SourceFileCoverageDataMap::const_iterator file = files.begin();
1102 E : const SourceFileCoverageData* data = NULL;
1103 E : for (; file != files.end(); ++file) {
1104 E : if (base::EndsWith(file->first, "coverage_tests.cc",
1105 : base::CompareCase::SENSITIVE)) {
1106 E : data = &file->second;
1107 E : break;
1108 : }
1109 E : }
1110 E : ASSERT_TRUE(data != NULL);
1111 :
1112 : // Validate function entry counts.
1113 : // Function: coverage_func1.
1114 E : EXPECT_TRUE(GetLineInfoExecution(data, 28));
1115 E : EXPECT_TRUE(GetLineInfoExecution(data, 29));
1116 :
1117 : // Function: coverage_func2.
1118 E : EXPECT_TRUE(GetLineInfoExecution(data, 35));
1119 E : EXPECT_TRUE(GetLineInfoExecution(data, 36));
1120 E : EXPECT_TRUE(GetLineInfoExecution(data, 37));
1121 E : EXPECT_FALSE(GetLineInfoExecution(data, 40));
1122 E : EXPECT_TRUE(GetLineInfoExecution(data, 42));
1123 :
1124 : // Function: coverage_func3.
1125 E : EXPECT_TRUE(GetLineInfoExecution(data, 47));
1126 E : EXPECT_FALSE(GetLineInfoExecution(data, 49));
1127 E : EXPECT_FALSE(GetLineInfoExecution(data, 50));
1128 E : EXPECT_TRUE(GetLineInfoExecution(data, 52));
1129 E : EXPECT_TRUE(GetLineInfoExecution(data, 54));
1130 E : }
1131 :
1132 : static bool ContainsString(const std::vector<std::wstring>& vec,
1133 E : const wchar_t* str) {
1134 E : return std::find(vec.begin(), vec.end(), str) != vec.end();
1135 E : }
1136 :
1137 E : void ProfileCheckTestDll(bool thunk_imports) {
1138 E : Parser parser;
1139 E : TestingProfileGrinder grinder;
1140 :
1141 : // Have the grinder aggregate all data to a single part.
1142 E : grinder.set_thread_parts(false);
1143 :
1144 : // Initialize trace parser.
1145 E : ASSERT_TRUE(parser.Init(&grinder));
1146 E : grinder.SetParser(&parser);
1147 :
1148 : // Add generated traces to the parser.
1149 E : QueueTraces(&parser);
1150 :
1151 : // Parse all traces.
1152 E : ASSERT_TRUE(parser.Consume());
1153 E : ASSERT_FALSE(parser.error_occurred());
1154 E : ASSERT_TRUE(grinder.Grind());
1155 :
1156 E : const TestingProfileGrinder::ModuleInformationSet& modules =
1157 : grinder.modules_;
1158 E : TestingProfileGrinder::ModuleInformationSet::const_iterator mod_it;
1159 E : std::vector<std::wstring> module_names;
1160 E : for (mod_it = modules.begin(); mod_it != modules.end(); ++mod_it) {
1161 E : base::FilePath image_name(mod_it->path);
1162 E : module_names.push_back(image_name.BaseName().value());
1163 E : }
1164 :
1165 E : EXPECT_TRUE(ContainsString(module_names,
1166 : testing::kIntegrationTestsDllName));
1167 : // If imports are thunked, we expect to find a module entry for the export
1168 : // DLL - otherwise it shouldn't be in there at all.
1169 E : if (thunk_imports) {
1170 E : EXPECT_TRUE(ContainsString(module_names, L"export_dll.dll"));
1171 E : } else {
1172 E : EXPECT_FALSE(ContainsString(module_names, L"export_dll.dll"));
1173 : }
1174 :
1175 : // Make sure at least one function we know of was hit.
1176 E : ASSERT_EQ(1U, grinder.parts_.size());
1177 E : const TestingProfileGrinder::PartData& data =
1178 : grinder.parts_.begin()->second;
1179 :
1180 : TestingProfileGrinder::InvocationNodeMap::const_iterator node_it =
1181 E : data.nodes_.begin();
1182 E : for (; node_it != data.nodes_.end(); ++node_it) {
1183 E : if (node_it->second.function.rva() == get_my_rva_)
1184 E : return;
1185 E : }
1186 :
1187 i : FAIL() << "Didn't find GetMyRVA function entry.";
1188 E : }
1189 :
1190 : // Helper function to test the Asan symbolizer script.
1191 : //
1192 : // It starts by running a test with the '--minidump_on_failure' flag turned
1193 : // on and then verify that the generated minidump can be symbolized correctly.
1194 : //
1195 : // @param test_id The test to run.
1196 : // @param kind The expected bad access kind.
1197 : // @param mode The expected bad access mode.
1198 : // @param size The expected bad access size.
1199 : // @param expect_corrupt_heap Indicates if we expect the heap to be corrupt.
1200 : void AsanSymbolizerTest(testing::EndToEndTestId test_id,
1201 : const char* kind,
1202 : const char* mode,
1203 : size_t size,
1204 E : bool expect_corrupt_heap) {
1205 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1206 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1207 :
1208 : // Make sure that a minidump gets produced by the logger when a bug occurs.
1209 E : std::unique_ptr<base::Environment> env(base::Environment::Create());
1210 E : ASSERT_NE(env.get(), nullptr);
1211 E : if (expect_corrupt_heap) {
1212 E : env->SetVar(::common::kSyzyAsanOptionsEnvVar, "--minidump_on_failure");
1213 E : } else {
1214 E : env->SetVar(::common::kSyzyAsanOptionsEnvVar,
1215 : "--minidump_on_failure --no_check_heap_on_failure");
1216 : }
1217 E : std::string log;
1218 :
1219 : // Run the test.
1220 E : OutOfProcessAsanErrorCheck(test_id, true, &log);
1221 :
1222 : // Look for the minidump path in the logger's output.
1223 E : pcrecpp::RE re("A minidump has been written to (.*\\.dmp)\\.\\n?");
1224 E : std::string minidump_path;
1225 E : EXPECT_TRUE(re.PartialMatch(log, &minidump_path));
1226 :
1227 : // Run the symbolizer tester script to make sure that the minidump gets
1228 : // symbolized correctly.
1229 :
1230 E : base::CommandLine cmd_line(
1231 : ::testing::GetSrcRelativePath(L"third_party/python_26/python.exe"));
1232 E : cmd_line.AppendArgPath(::testing::GetSrcRelativePath(
1233 : L"syzygy/scripts/asan/minidump_symbolizer_tester.py"));
1234 E : cmd_line.AppendArg(base::StringPrintf("--minidump=%s",
1235 : minidump_path.c_str()));
1236 E : cmd_line.AppendArg(base::StringPrintf("--bug-type=%s", kind));
1237 E : cmd_line.AppendArg(base::StringPrintf("--access-mode=%s", mode));
1238 E : cmd_line.AppendArg(base::StringPrintf("--access-size=%d", size));
1239 E : if (expect_corrupt_heap)
1240 E : cmd_line.AppendArg("--corrupt-heap");
1241 :
1242 E : base::LaunchOptions options;
1243 E : options.inherit_handles = true;
1244 E : base::Process process = base::LaunchProcess(cmd_line, options);
1245 E : EXPECT_TRUE(process.IsValid());
1246 :
1247 E : int exit_code = 0;
1248 E : EXPECT_TRUE(process.WaitForExit(&exit_code));
1249 E : EXPECT_EQ(0u, exit_code);
1250 :
1251 : // Check if the minidump contains a valid protobuf.
1252 E : poirot::MinidumpProcessor poirot_processor(
1253 : base::FilePath::FromUTF8Unsafe(minidump_path));
1254 E : EXPECT_TRUE(poirot_processor.ProcessDump());
1255 :
1256 E : env->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
1257 E : }
1258 :
1259 : // Stashes the current log-level before each test instance and restores it
1260 : // after each test completes.
1261 : testing::ScopedLogLevelSaver log_level_saver;
1262 :
1263 : // @name The application under test.
1264 : // @{
1265 : TestApp test_app_;
1266 : TestApp::Implementation& test_impl_;
1267 : base::FilePath temp_dir_;
1268 : base::FilePath stdin_path_;
1269 : base::FilePath stdout_path_;
1270 : base::FilePath stderr_path_;
1271 : // @}
1272 :
1273 : // @name Command-line, parameters and outputs.
1274 : // @{
1275 : base::CommandLine cmd_line_;
1276 : base::FilePath input_dll_path_;
1277 : base::FilePath output_dll_path_;
1278 : base::FilePath traces_dir_;
1279 : // @}
1280 :
1281 : // The test_dll module.
1282 : testing::ScopedHMODULE module_;
1283 :
1284 : // Our call trace service process instance.
1285 : testing::CallTraceService service_;
1286 :
1287 : // Decomposed image.
1288 : pe::PEFile pe_image_;
1289 : pe::ImageLayout image_layout_;
1290 : block_graph::BlockGraph block_graph_;
1291 : uint32_t get_my_rva_;
1292 E : };
1293 : typedef testing::StrictMock<LenientInstrumentAppIntegrationTest>
1294 : InstrumentAppIntegrationTest;
1295 :
1296 : typedef std::map<std::string, size_t> FunctionOffsetMap;
1297 :
1298 : // A utility transform for extracting call site offsets from blocks.
1299 : // Used by GetCallOffsets and ZebraBlockHeap tests.
1300 : class ExtractCallTransform
1301 : : public block_graph::BasicBlockSubGraphTransformInterface {
1302 : public:
1303 E : explicit ExtractCallTransform(FunctionOffsetMap* map) : map_(map) { }
1304 E : virtual ~ExtractCallTransform() { }
1305 i : virtual const char* name() const { return "ExtractCallTransform"; }
1306 :
1307 : virtual bool TransformBasicBlockSubGraph(
1308 : const block_graph::TransformPolicyInterface* policy,
1309 : block_graph::BlockGraph* block_graph,
1310 E : block_graph::BasicBlockSubGraph* basic_block_subgraph) {
1311 E : for (auto& desc : basic_block_subgraph->block_descriptions()) {
1312 E : auto map_it = map_->find(desc.name);
1313 E : if (map_it == map_->end())
1314 E : continue;
1315 :
1316 : // Set this to effectively 'infinite' to start with.
1317 E : map_it->second = static_cast<size_t>(-1);
1318 :
1319 E : for (auto& bb : desc.basic_block_order) {
1320 : block_graph::BasicCodeBlock* bcb =
1321 E : block_graph::BasicCodeBlock::Cast(bb);
1322 E : if (bcb == nullptr)
1323 E : continue;
1324 :
1325 E : size_t offset = bcb->offset();
1326 E : for (auto& inst : bcb->instructions()) {
1327 E : offset += inst.size();
1328 E : if (inst.IsCall()) {
1329 E : map_it->second = std::min(map_it->second, offset);
1330 : }
1331 E : }
1332 E : }
1333 E : }
1334 :
1335 E : return true;
1336 E : }
1337 :
1338 : protected:
1339 : FunctionOffsetMap* map_;
1340 : };
1341 :
1342 : // Gets the offsets of the first call from each function named in |map|,
1343 : // as found in the image at |image_path|. Updates the map with the offsets.
1344 : void GetCallOffsets(const base::FilePath& image_path,
1345 E : FunctionOffsetMap* map) {
1346 E : pe::PEFile pe_file;
1347 E : ASSERT_TRUE(pe_file.Init(image_path));
1348 E : block_graph::BlockGraph bg;
1349 E : block_graph::BlockGraph::Block* header = NULL;
1350 :
1351 : // Decompose the image.
1352 : {
1353 E : pe::ImageLayout image_layout(&bg);
1354 E : pe::Decomposer decomposer(pe_file);
1355 E : ASSERT_TRUE(decomposer.Decompose(&image_layout));
1356 E : header = image_layout.blocks.GetBlockByAddress(
1357 : block_graph::BlockGraph::RelativeAddress(0));
1358 E : }
1359 :
1360 : // Apply the Asan transform.
1361 E : pe::PETransformPolicy policy;
1362 : {
1363 E : instrument::transforms::AsanTransform tx;
1364 E : ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
1365 E : &tx, &policy, &bg, header));
1366 E : }
1367 :
1368 : // Apply our dummy transform which simply extracts call addresses.
1369 : {
1370 E : ExtractCallTransform bbtx(map);
1371 E : block_graph::transforms::ChainedBasicBlockTransforms tx;
1372 E : tx.AppendTransform(&bbtx);
1373 E : ASSERT_TRUE(block_graph::ApplyBlockGraphTransform(
1374 E : &tx, &policy, &bg, header));
1375 E : }
1376 E : }
1377 :
1378 E : void LenientInstrumentAppIntegrationTest::AsanZebraHeapTest(bool enabled) {
1379 : // Find the offset of the call we want to instrument.
1380 : static const char kTest1[] =
1381 : "testing::AsanReadPageAllocationTrailerBeforeFree";
1382 : static const char kTest2[] =
1383 : "testing::AsanWritePageAllocationBodyAfterFree";
1384 E : FunctionOffsetMap map({{kTest1, -1}, {kTest2, -1}});
1385 E : ASSERT_NO_FATAL_FAILURE(GetCallOffsets(input_dll_path_, &map));
1386 :
1387 : // Create an allocation filter.
1388 E : base::FilePath filter_path = temp_dir_.AppendASCII("allocation_filter.json");
1389 E : std::string filter_contents = base::StringPrintf(
1390 : "{\"hooks\":{\"%s\":[%d],\"%s\":[%d]}}",
1391 : kTest1, map[kTest1], kTest2, map[kTest2]);
1392 E : base::WriteFile(
1393 : filter_path, filter_contents.c_str(), filter_contents.size());
1394 :
1395 : // Configure the transform and test the binary.
1396 E : cmd_line_.AppendSwitchPath("allocation-filter-config-file", filter_path);
1397 E : std::string rtl_options = "--no_check_heap_on_failure";
1398 E : if (enabled)
1399 E : rtl_options += " --enable_zebra_block_heap --enable_allocation_filter";
1400 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", rtl_options);
1401 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1402 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1403 :
1404 : // Run tests that are specific to the zebra block heap.
1405 E : OutOfProcessAsanErrorCheckAndValidateLog(
1406 : testing::kAsanReadPageAllocationTrailerBeforeFreeAllocation, enabled,
1407 : kAsanAccessViolationLog, kAsanHeapBufferOverflow);
1408 E : OutOfProcessAsanErrorCheckAndValidateLog(
1409 : testing::kAsanWritePageAllocationBodyAfterFree, enabled,
1410 : kAsanAccessViolationLog, kAsanHeapUseAfterFree);
1411 E : }
1412 :
1413 : } // namespace
1414 :
1415 E : TEST_F(InstrumentAppIntegrationTest, AsanEndToEnd) {
1416 : // Disable the heap checking as this is implies touching all the shadow bytes
1417 : // and this make those tests really slow.
1418 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", "--no_check_heap_on_failure");
1419 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1420 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1421 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1422 E : ASSERT_NO_FATAL_FAILURE(CheckTestDllImportsRedirected());
1423 E : }
1424 :
1425 E : TEST_F(InstrumentAppIntegrationTest, AsanEndToEndNoLiveness) {
1426 : // Disable the heap checking as this is implies touching all the shadow bytes
1427 : // and this make those tests really slow.
1428 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", "--no_check_heap_on_failure");
1429 E : cmd_line_.AppendSwitch("no-liveness-analysis");
1430 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1431 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1432 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1433 E : }
1434 :
1435 E : TEST_F(InstrumentAppIntegrationTest, AsanEndToEndNoRedundancyAnalysis) {
1436 : // Disable the heap checking as this is implies touching all the shadow bytes
1437 : // and this make those tests really slow.
1438 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", "--no_check_heap_on_failure");
1439 E : cmd_line_.AppendSwitch("no-redundancy-analysis");
1440 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1441 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1442 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1443 E : }
1444 :
1445 E : TEST_F(InstrumentAppIntegrationTest, AsanEndToEndNoFunctionInterceptors) {
1446 : // Disable the heap checking as this is implies touching all the shadow bytes
1447 : // and this make those tests really slow.
1448 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", "--no_check_heap_on_failure");
1449 E : cmd_line_.AppendSwitch("no-interceptors");
1450 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1451 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1452 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1453 E : }
1454 :
1455 E : TEST_F(InstrumentAppIntegrationTest, AsanEndToEndWithRtlOptions) {
1456 E : cmd_line_.AppendSwitchASCII(
1457 : "asan-rtl-options",
1458 : "--quarantine_size=20000000 --quarantine_block_size=1000000 "
1459 : "--no_check_heap_on_failure");
1460 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1461 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1462 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1463 :
1464 : // Get the active runtime and validate its parameters.
1465 E : agent::asan::AsanRuntime* runtime = GetActiveAsanRuntime();
1466 E : ASSERT_TRUE(runtime != NULL);
1467 E : ASSERT_EQ(20000000u, runtime->params().quarantine_size);
1468 E : ASSERT_EQ(1000000u, runtime->params().quarantine_block_size);
1469 E : }
1470 :
1471 E : TEST_F(InstrumentAppIntegrationTest,
1472 E : AsanEndToEndWithRtlOptionsOverrideWithEnvironment) {
1473 E : std::unique_ptr<base::Environment> env(base::Environment::Create());
1474 E : ASSERT_NE(env.get(), nullptr);
1475 E : env->SetVar(::common::kSyzyAsanOptionsEnvVar,
1476 : "--quarantine_block_size=800000 --ignored_stack_ids=0x1 "
1477 : "--no_check_heap_on_failure");
1478 E : cmd_line_.AppendSwitchASCII(
1479 : "asan-rtl-options",
1480 : "--quarantine_size=20000000 --quarantine_block_size=1000000 "
1481 : "--ignored_stack_ids=0x2");
1482 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1483 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1484 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1485 :
1486 : // Get the active runtime and validate its parameters.
1487 E : agent::asan::AsanRuntime* runtime = GetActiveAsanRuntime();
1488 E : ASSERT_TRUE(runtime != NULL);
1489 E : ASSERT_EQ(20000000u, runtime->params().quarantine_size);
1490 E : ASSERT_EQ(800000u, runtime->params().quarantine_block_size);
1491 E : ASSERT_THAT(runtime->params().ignored_stack_ids_set,
1492 E : testing::ElementsAre(0x1, 0x2));
1493 :
1494 E : env->UnSetVar(::common::kSyzyAsanOptionsEnvVar);
1495 E : }
1496 :
1497 E : TEST_F(InstrumentAppIntegrationTest, FullOptimizedAsanEndToEnd) {
1498 : // Disable the heap checking as this implies touching all the shadow bytes
1499 : // and this make these tests really slow.
1500 E : cmd_line_.AppendSwitchASCII("asan-rtl-options", "--no_check_heap_on_failure");
1501 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1502 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1503 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckTestDll());
1504 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckInterceptedFunctions());
1505 E : }
1506 :
1507 E : TEST_F(InstrumentAppIntegrationTest,
1508 E : AsanInvalidAccessWithCorruptAllocatedBlockHeader) {
1509 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1510 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1511 E : OutOfProcessAsanErrorCheckAndValidateLog(
1512 : testing::kAsanInvalidAccessWithCorruptAllocatedBlockHeader, true,
1513 : kAsanCorruptHeap, NULL);
1514 E : }
1515 :
1516 E : TEST_F(InstrumentAppIntegrationTest,
1517 E : AsanHeapCheckerCallsReportCrashWithProtobuf) {
1518 : // Heap checker failures do get reported to ReportCrashWithProtobuf if it is
1519 : // defined.
1520 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1521 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1522 :
1523 E : int exit_code = RunOutOfProcessFunction(
1524 : L"report_crash_with_protobuf_harness.exe",
1525 : testing::kAsanInvalidAccessWithCorruptAllocatedBlockHeader, true);
1526 E : EXPECT_EQ(kExeReportCrashWithProtobufExitCode, exit_code);
1527 E : }
1528 :
1529 E : TEST_F(InstrumentAppIntegrationTest, AsanOverflowCallsCrashForException) {
1530 : // Asan-detected violations go through CrashForException if it is available.
1531 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1532 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1533 : int exit_code =
1534 E : RunOutOfProcessFunction(L"crash_for_exception_harness.exe",
1535 : testing::kAsanRead8BufferOverflow, true);
1536 E : EXPECT_EQ(kExeCrashForExceptionExitCode, exit_code);
1537 E : }
1538 :
1539 E : TEST_F(InstrumentAppIntegrationTest,
1540 E : AsanOverflowCallsReportCrashWithProtobuf) {
1541 : // Asan-detected violations go through ReportCrashWithProtobuf if it is
1542 : // available.
1543 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1544 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1545 : int exit_code =
1546 E : RunOutOfProcessFunction(L"report_crash_with_protobuf_harness.exe",
1547 : testing::kAsanRead8BufferOverflow, true);
1548 E : EXPECT_EQ(kExeReportCrashWithProtobufExitCode, exit_code);
1549 E : }
1550 :
1551 E : TEST_F(InstrumentAppIntegrationTest,
1552 E : AsanInvalidAccessWithCorruptAllocatedBlockTrailer) {
1553 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1554 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1555 E : OutOfProcessAsanErrorCheckAndValidateLog(
1556 : testing::kAsanInvalidAccessWithCorruptAllocatedBlockTrailer, true,
1557 : kAsanCorruptHeap, NULL);
1558 E : }
1559 :
1560 E : TEST_F(InstrumentAppIntegrationTest,
1561 E : AsanInvalidAccessWithCorruptFreedBlock) {
1562 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1563 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1564 E : OutOfProcessAsanErrorCheckAndValidateLog(
1565 : testing::kAsanInvalidAccessWithCorruptFreedBlock, true, kAsanCorruptHeap,
1566 : NULL);
1567 E : }
1568 :
1569 E : TEST_F(InstrumentAppIntegrationTest, AsanCorruptBlockWithPageProtections) {
1570 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1571 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1572 E : OutOfProcessAsanErrorCheckAndValidateLog(
1573 : testing::kAsanCorruptBlockWithPageProtections, true,
1574 : kAsanHeapUseAfterFree, kAsanCorruptHeap);
1575 E : }
1576 :
1577 E : TEST_F(InstrumentAppIntegrationTest, SampledAllocationsAsanEndToEnd) {
1578 E : cmd_line_.AppendSwitchASCII("asan-rtl-options",
1579 : "--allocation_guard_rate=0.5 "
1580 : "--no_check_heap_on_failure");
1581 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1582 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1583 E : ASSERT_NO_FATAL_FAILURE(AsanErrorCheckSampledAllocations());
1584 E : }
1585 :
1586 E : TEST_F(InstrumentAppIntegrationTest, AsanLargeBlockHeapEnabledTest) {
1587 E : cmd_line_.AppendSwitchASCII("asan-rtl-options",
1588 : "--no_check_heap_on_failure "
1589 : "--quarantine_size=4000000 "
1590 : "--quarantine_block_size=2000000");
1591 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1592 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1593 E : ASSERT_NO_FATAL_FAILURE(AsanLargeBlockHeapTests(true));
1594 E : }
1595 :
1596 E : TEST_F(InstrumentAppIntegrationTest, AsanLargeBlockHeapDisabledTest) {
1597 E : cmd_line_.AppendSwitchASCII("asan-rtl-options",
1598 : "--no_check_heap_on_failure "
1599 : "--disable_large_block_heap");
1600 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1601 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1602 E : ASSERT_NO_FATAL_FAILURE(AsanLargeBlockHeapTests(false));
1603 E : }
1604 :
1605 E : TEST_F(InstrumentAppIntegrationTest, AsanZebraHeapDisabledTest) {
1606 E : AsanZebraHeapTest(false);
1607 E : }
1608 :
1609 E : TEST_F(InstrumentAppIntegrationTest, AsanZebraHeapEnabledTest) {
1610 E : AsanZebraHeapTest(true);
1611 E : }
1612 :
1613 E : TEST_F(InstrumentAppIntegrationTest, AsanSymbolizerTestAsanBufferOverflow) {
1614 E : AsanSymbolizerTest(testing::kAsanRead8BufferOverflow,
1615 : STRINGIFY(HEAP_BUFFER_OVERFLOW),
1616 : STRINGIFY(ASAN_READ_ACCESS),
1617 : 1,
1618 : false);
1619 E : }
1620 :
1621 E : TEST_F(InstrumentAppIntegrationTest, AsanSymbolizerTestAsanBufferUnderflow) {
1622 E : AsanSymbolizerTest(testing::kAsanWrite32BufferUnderflow,
1623 : STRINGIFY(HEAP_BUFFER_UNDERFLOW),
1624 : STRINGIFY(ASAN_WRITE_ACCESS),
1625 : 4,
1626 : false);
1627 E : }
1628 :
1629 E : TEST_F(InstrumentAppIntegrationTest, AsanSymbolizerTestAsanUseAfterFree) {
1630 E : AsanSymbolizerTest(testing::kAsanRead64UseAfterFree,
1631 : STRINGIFY(USE_AFTER_FREE),
1632 : STRINGIFY(ASAN_READ_ACCESS),
1633 : 8,
1634 : false);
1635 E : }
1636 :
1637 E : TEST_F(InstrumentAppIntegrationTest, AsanSymbolizerTestAsanCorruptBlock) {
1638 E : AsanSymbolizerTest(testing::kAsanCorruptBlock,
1639 : STRINGIFY(CORRUPT_BLOCK),
1640 : STRINGIFY(ASAN_UNKNOWN_ACCESS),
1641 : 0,
1642 : false);
1643 E : }
1644 :
1645 E : TEST_F(InstrumentAppIntegrationTest,
1646 E : AsanSymbolizerTestAsanCorruptBlockInQuarantine) {
1647 E : AsanSymbolizerTest(testing::kAsanCorruptBlockInQuarantine,
1648 : STRINGIFY(CORRUPT_BLOCK),
1649 : STRINGIFY(ASAN_UNKNOWN_ACCESS),
1650 : 0,
1651 : true);
1652 E : }
1653 :
1654 : // These tests require corrupt heap checking to be enabled.
1655 E : TEST_F(InstrumentAppIntegrationTest, AsanNearNullptrAccess) {
1656 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("asan"));
1657 :
1658 E : OutOfProcessAsanErrorCheckAndValidateLog(
1659 : testing::kAsanNearNullptrAccessHeapCorruptionInstrumented, true,
1660 : kAsanHandlingException, kAsanNearNullptrAccessHeapCorruption);
1661 E : OutOfProcessAsanErrorCheckAndValidateLog(
1662 : testing::kAsanNearNullptrAccessHeapCorruptionUninstrumented, true,
1663 : kAsanHandlingException, kAsanNearNullptrAccessHeapCorruption);
1664 E : OutOfProcessAsanErrorCheckAndValidateLog(
1665 : testing::kAsanNearNullptrAccessNoHeapCorruptionInstrumented, true,
1666 : kAsanHandlingException, kAsanNearNullptrAccessNoHeapCorruption);
1667 E : OutOfProcessAsanErrorCheckAndValidateLog(
1668 : testing::kAsanNearNullptrAccessNoHeapCorruptionUninstrumented, true,
1669 : kAsanHandlingException, kAsanNearNullptrAccessNoHeapCorruption);
1670 E : OutOfProcessAsanErrorCheckAndValidateLog(
1671 : testing::kAsanNullptrAccessNoHeapCorruptionUninstrumented, true,
1672 : kAsanHandlingException, kAsanNearNullptrAccessNoHeapCorruption);
1673 E : }
1674 :
1675 E : TEST_F(InstrumentAppIntegrationTest, BBEntryEndToEnd) {
1676 E : ASSERT_NO_FATAL_FAILURE(StartService());
1677 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("bbentry"));
1678 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1679 E : ASSERT_NO_FATAL_FAILURE(BBEntryInvokeTestDll());
1680 E : ASSERT_NO_FATAL_FAILURE(StopService());
1681 E : ASSERT_NO_FATAL_FAILURE(BBEntryCheckTestDll());
1682 E : }
1683 :
1684 E : TEST_F(InstrumentAppIntegrationTest, BranchEndToEnd) {
1685 E : ASSERT_NO_FATAL_FAILURE(StartService());
1686 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("branch"));
1687 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1688 E : ASSERT_NO_FATAL_FAILURE(BBEntryInvokeTestDll());
1689 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1690 E : ASSERT_NO_FATAL_FAILURE(StopService());
1691 E : ASSERT_NO_FATAL_FAILURE(BranchCheckTestDll());
1692 E : }
1693 :
1694 E : TEST_F(InstrumentAppIntegrationTest, BranchWithBufferingEndToEnd) {
1695 E : cmd_line_.AppendSwitch("buffering");
1696 E : ASSERT_NO_FATAL_FAILURE(StartService());
1697 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("branch"));
1698 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1699 E : ASSERT_NO_FATAL_FAILURE(BBEntryInvokeTestDll());
1700 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1701 E : ASSERT_NO_FATAL_FAILURE(StopService());
1702 E : ASSERT_NO_FATAL_FAILURE(BranchCheckTestDll());
1703 E : }
1704 :
1705 E : TEST_F(InstrumentAppIntegrationTest, BranchWithSlotEndToEnd) {
1706 E : cmd_line_.AppendSwitchASCII("fs-slot", "1");
1707 E : ASSERT_NO_FATAL_FAILURE(StartService());
1708 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("branch"));
1709 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1710 E : ASSERT_NO_FATAL_FAILURE(BBEntryInvokeTestDll());
1711 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1712 E : ASSERT_NO_FATAL_FAILURE(StopService());
1713 E : ASSERT_NO_FATAL_FAILURE(BranchCheckTestDll());
1714 E : }
1715 :
1716 E : TEST_F(InstrumentAppIntegrationTest, BranchWithSlotAndBufferingEndToEnd) {
1717 E : cmd_line_.AppendSwitch("buffering");
1718 E : cmd_line_.AppendSwitchASCII("fs-slot", "1");
1719 E : ASSERT_NO_FATAL_FAILURE(StartService());
1720 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("branch"));
1721 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1722 E : ASSERT_NO_FATAL_FAILURE(BBEntryInvokeTestDll());
1723 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1724 E : ASSERT_NO_FATAL_FAILURE(StopService());
1725 E : ASSERT_NO_FATAL_FAILURE(BranchCheckTestDll());
1726 E : }
1727 :
1728 E : TEST_F(InstrumentAppIntegrationTest, CallTraceEndToEnd) {
1729 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("calltrace"));
1730 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1731 E : }
1732 :
1733 E : TEST_F(InstrumentAppIntegrationTest, CoverageEndToEnd) {
1734 E : base::win::ScopedCOMInitializer scoped_com_initializer;
1735 E : ASSERT_NO_FATAL_FAILURE(StartService());
1736 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("coverage"));
1737 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1738 E : ASSERT_NO_FATAL_FAILURE(CoverageInvokeTestDll());
1739 E : ASSERT_NO_FATAL_FAILURE(StopService());
1740 E : ASSERT_NO_FATAL_FAILURE(CoverageCheckTestDll());
1741 E : }
1742 :
1743 E : TEST_F(InstrumentAppIntegrationTest, BBEntryCoverageEndToEnd) {
1744 : // Coverage grinder must be able to process traces produced by bbentry
1745 : // instrumentation.
1746 E : base::win::ScopedCOMInitializer scoped_com_initializer;
1747 E : ASSERT_NO_FATAL_FAILURE(StartService());
1748 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("bbentry"));
1749 E : ASSERT_NO_FATAL_FAILURE(EndToEndCheckTestDll());
1750 E : ASSERT_NO_FATAL_FAILURE(CoverageInvokeTestDll());
1751 E : ASSERT_NO_FATAL_FAILURE(StopService());
1752 E : ASSERT_NO_FATAL_FAILURE(CoverageCheckTestDll());
1753 E : }
1754 :
1755 E : TEST_F(InstrumentAppIntegrationTest, ProfileEndToEnd) {
1756 E : ASSERT_NO_FATAL_FAILURE(StartService());
1757 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("profile"));
1758 E : ASSERT_NO_FATAL_FAILURE(ProfileInvokeTestDll());
1759 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1760 E : ASSERT_NO_FATAL_FAILURE(StopService());
1761 E : ASSERT_NO_FATAL_FAILURE(ProfileCheckTestDll(false));
1762 E : }
1763 :
1764 E : TEST_F(InstrumentAppIntegrationTest, ProfileWithImportsEndToEnd) {
1765 E : cmd_line_.AppendSwitch("instrument-imports");
1766 E : ASSERT_NO_FATAL_FAILURE(StartService());
1767 E : ASSERT_NO_FATAL_FAILURE(EndToEndTest("profile"));
1768 E : ASSERT_NO_FATAL_FAILURE(ProfileInvokeTestDll());
1769 E : ASSERT_NO_FATAL_FAILURE(UnloadDll());
1770 E : ASSERT_NO_FATAL_FAILURE(StopService());
1771 E : ASSERT_NO_FATAL_FAILURE(ProfileCheckTestDll(true));
1772 E : }
1773 :
1774 : } // namespace integration_tests
|