1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/crash/core/app/fallback_crash_handling_win.h"
6 
7 #include "base/base_switches.h"
8 #include "base/check.h"
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/test/multiprocess_test.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "testing/multiprocess_func_list.h"
15 #include "third_party/crashpad/crashpad/client/crash_report_database.h"
16 
17 namespace crash_reporter {
18 
19 namespace {
20 
21 const DWORD kExceptionCode = 0xCAFEBABE;
22 
23 // This main function runs in two modes, first as a faux-crashpad handler,
24 // and then with --type=fallback-handler to handle the crash in the first
25 // instance.
MULTIPROCESS_TEST_MAIN(FallbackCrashHandlingWinRunHandler)26 MULTIPROCESS_TEST_MAIN(FallbackCrashHandlingWinRunHandler) {
27   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
28   if (cmd_line->GetSwitchValueASCII("type") ==
29       switches::kFallbackCrashHandler) {
30     return RunAsFallbackCrashHandler(*cmd_line,
31                                      "FallbackCrashHandlingWinRunHandler",
32                                      "1.2.3.4", "FakeChannel");
33   }
34 
35   CHECK(SetupFallbackCrashHandling(*cmd_line));
36 
37   // Provoke a crash with a well-defined exception code.
38   // The process shouldn't terminate with this exception code.
39   RaiseException(kExceptionCode, 0, 0, nullptr);
40 
41   // This process should never return from the exception.
42   CHECK(false) << "Unexpected return from RaiseException";
43 
44   // Should never get here.
45   return 0;
46 }
47 
48 class FallbackCrashHandlingTest : public base::MultiProcessTest {
49  public:
SetUp()50   void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); }
51 
52  protected:
53   base::ScopedTempDir database_dir_;
54 };
55 
56 }  // namespace
57 
TEST_F(FallbackCrashHandlingTest,SetupAndRunAsFallbackCrashHandler)58 TEST_F(FallbackCrashHandlingTest, SetupAndRunAsFallbackCrashHandler) {
59   // Launch a subprocess to test the fallback handling implementation.
60   base::CommandLine cmd_line = base::GetMultiProcessTestChildBaseCommandLine();
61   cmd_line.AppendSwitchPath("database", database_dir_.GetPath());
62 
63   base::LaunchOptions options;
64   options.start_hidden = true;
65   base::Process test_child = base::SpawnMultiProcessTestChild(
66       "FallbackCrashHandlingWinRunHandler", cmd_line, options);
67 
68   ASSERT_TRUE(test_child.IsValid());
69   int exit_code = -1;
70   ASSERT_TRUE(test_child.WaitForExit(&exit_code));
71   ASSERT_EQ(kFallbackCrashTerminationCode, static_cast<uint32_t>(exit_code));
72 
73   // Validate that the database contains one valid crash dump.
74   std::unique_ptr<crashpad::CrashReportDatabase> database =
75       crashpad::CrashReportDatabase::InitializeWithoutCreating(
76           database_dir_.GetPath());
77 
78   std::vector<crashpad::CrashReportDatabase::Report> reports;
79   ASSERT_EQ(crashpad::CrashReportDatabase::kNoError,
80             database->GetPendingReports(&reports));
81 
82   EXPECT_EQ(1U, reports.size());
83 }
84 
85 }  // namespace crash_reporter
86