// 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 #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