|  | // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "components/browser_watcher/stability_debugging.h" | 
|  |  | 
|  | #include <windows.h> | 
|  |  | 
|  | #include "base/command_line.h" | 
|  | #include "base/debug/activity_tracker.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/files/scoped_temp_dir.h" | 
|  | #include "base/process/process.h" | 
|  | #include "base/test/multiprocess_test.h" | 
|  | #include "base/test/test_timeouts.h" | 
|  | #include "build/build_config.h" | 
|  | #include "components/browser_watcher/stability_report.pb.h" | 
|  | #include "components/browser_watcher/stability_report_extractor.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "testing/multiprocess_func_list.h" | 
|  |  | 
|  | namespace browser_watcher { | 
|  |  | 
|  | using base::debug::GlobalActivityTracker; | 
|  |  | 
|  | const int kMemorySize = 1 << 20;  // 1MiB | 
|  | const uint32_t exception_code = 42U; | 
|  | const uint32_t exception_flag_continuable = 0U; | 
|  |  | 
|  | class StabilityDebuggingTest : public testing::Test { | 
|  | public: | 
|  | StabilityDebuggingTest() {} | 
|  | ~StabilityDebuggingTest() override { | 
|  | GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); | 
|  | if (global_tracker) { | 
|  | global_tracker->ReleaseTrackerForCurrentThreadForTesting(); | 
|  | delete global_tracker; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SetUp() override { | 
|  | testing::Test::SetUp(); | 
|  |  | 
|  | ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 
|  | debug_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); | 
|  |  | 
|  | GlobalActivityTracker::CreateWithFile(debug_path_, kMemorySize, 0ULL, "", | 
|  | 3); | 
|  | } | 
|  |  | 
|  | const base::FilePath& debug_path() { return debug_path_; } | 
|  |  | 
|  | private: | 
|  | base::ScopedTempDir temp_dir_; | 
|  | base::FilePath debug_path_; | 
|  | }; | 
|  |  | 
|  | #if defined(ADDRESS_SANITIZER) && defined(OS_WIN) | 
|  | // The test does not pass under WinASan. See crbug.com/809524. | 
|  | #define MAYBE_CrashingTest DISABLED_CrashingTest | 
|  | #else | 
|  | #define MAYBE_CrashingTest CrashingTest | 
|  | #endif | 
|  | TEST_F(StabilityDebuggingTest, MAYBE_CrashingTest) { | 
|  | RegisterStabilityVEH(); | 
|  |  | 
|  | // Raise an exception, then continue. | 
|  | __try { | 
|  | ::RaiseException(exception_code, exception_flag_continuable, 0U, nullptr); | 
|  | } __except (EXCEPTION_CONTINUE_EXECUTION) { | 
|  | } | 
|  |  | 
|  | // Collect the report. | 
|  | StabilityReport report; | 
|  | ASSERT_EQ(SUCCESS, Extract(debug_path(), &report)); | 
|  |  | 
|  | // Validate expectations. | 
|  | ASSERT_EQ(1, report.process_states_size()); | 
|  | const ProcessState& process_state = report.process_states(0); | 
|  | ASSERT_EQ(1, process_state.threads_size()); | 
|  |  | 
|  | bool thread_found = false; | 
|  | for (const ThreadState& thread : process_state.threads()) { | 
|  | if (thread.thread_id() == ::GetCurrentThreadId()) { | 
|  | thread_found = true; | 
|  | ASSERT_TRUE(thread.has_exception()); | 
|  | const Exception& exception = thread.exception(); | 
|  | EXPECT_EQ(exception_code, exception.code()); | 
|  | EXPECT_NE(0ULL, exception.program_counter()); | 
|  | EXPECT_NE(0ULL, exception.exception_address()); | 
|  | EXPECT_NE(0LL, exception.time()); | 
|  | } | 
|  | } | 
|  | ASSERT_TRUE(thread_found); | 
|  | } | 
|  |  | 
|  | }  // namespace browser_watcher |