blob: ce316774891bbd6c72b2d37412bbe25b07acf61c [file] [log] [blame]
Yavor Goulishev9c08e842020-04-29 14:03:33 -07001// Copyright 2015 The Crashpad Authors. 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 "util/win/exception_handler_server.h"
16
17#include <windows.h>
18#include <sys/types.h>
19
20#include <string>
21#include <vector>
22
23#include "base/macros.h"
24#include "base/strings/utf_string_conversions.h"
25#include "client/crashpad_client.h"
26#include "gtest/gtest.h"
27#include "test/win/win_child_process.h"
28#include "util/thread/thread.h"
29#include "util/win/address_types.h"
30#include "util/win/registration_protocol_win.h"
31#include "util/win/scoped_handle.h"
32
33namespace crashpad {
34namespace test {
35namespace {
36
37// Runs the ExceptionHandlerServer on a background thread.
38class RunServerThread : public Thread {
39 public:
40 // Instantiates a thread which will invoke server->Run(delegate).
41 RunServerThread(ExceptionHandlerServer* server,
42 ExceptionHandlerServer::Delegate* delegate)
43 : server_(server), delegate_(delegate) {}
44 ~RunServerThread() override {}
45
46 private:
47 // Thread:
48 void ThreadMain() override { server_->Run(delegate_); }
49
50 ExceptionHandlerServer* server_;
51 ExceptionHandlerServer::Delegate* delegate_;
52
53 DISALLOW_COPY_AND_ASSIGN(RunServerThread);
54};
55
56class TestDelegate : public ExceptionHandlerServer::Delegate {
57 public:
58 explicit TestDelegate(HANDLE server_ready) : server_ready_(server_ready) {}
59 ~TestDelegate() {}
60
61 void ExceptionHandlerServerStarted() override {
62 SetEvent(server_ready_);
63 }
64 unsigned int ExceptionHandlerServerException(
65 HANDLE process,
66 WinVMAddress exception_information_address,
67 WinVMAddress debug_critical_section_address) override {
68 return 0;
69 }
70
71 void WaitForStart() { WaitForSingleObject(server_ready_, INFINITE); }
72
73 private:
74 HANDLE server_ready_; // weak
75
76 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
77};
78
79class ExceptionHandlerServerTest : public testing::Test {
80 public:
81 ExceptionHandlerServerTest()
82 : server_(true),
83 pipe_name_(L"\\\\.\\pipe\\test_name"),
84 server_ready_(CreateEvent(nullptr, false, false, nullptr)),
85 delegate_(server_ready_.get()),
86 server_thread_(&server_, &delegate_) {
87 server_.SetPipeName(pipe_name_);
88 }
89
90 TestDelegate& delegate() { return delegate_; }
91 ExceptionHandlerServer& server() { return server_; }
92 Thread& server_thread() { return server_thread_; }
93 const std::wstring& pipe_name() const { return pipe_name_; }
94
95 private:
96 ExceptionHandlerServer server_;
97 std::wstring pipe_name_;
98 ScopedKernelHANDLE server_ready_;
99 TestDelegate delegate_;
100 RunServerThread server_thread_;
101
102 DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerServerTest);
103};
104
105// During destruction, ensures that the server is stopped and the background
106// thread joined.
107class ScopedStopServerAndJoinThread {
108 public:
109 ScopedStopServerAndJoinThread(ExceptionHandlerServer* server, Thread* thread)
110 : server_(server), thread_(thread) {}
111 ~ScopedStopServerAndJoinThread() {
112 server_->Stop();
113 thread_->Join();
114 }
115
116 private:
117 ExceptionHandlerServer* server_;
118 Thread* thread_;
119 DISALLOW_COPY_AND_ASSIGN(ScopedStopServerAndJoinThread);
120};
121
122TEST_F(ExceptionHandlerServerTest, Instantiate) {
123}
124
125TEST_F(ExceptionHandlerServerTest, StartAndStop) {
126 server_thread().Start();
127 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
128 &server(), &server_thread());
129 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
130}
131
132TEST_F(ExceptionHandlerServerTest, StopWhileConnected) {
133 server_thread().Start();
134 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
135 &server(), &server_thread());
136 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
137 CrashpadClient client;
138 client.SetHandlerIPCPipe(pipe_name());
139 // Leaving this scope causes the server to be stopped, while the connection
140 // is still open.
141}
142
143std::wstring ReadWString(FileHandle handle) {
144 size_t length = 0;
145 EXPECT_TRUE(LoggingReadFileExactly(handle, &length, sizeof(length)));
146 std::wstring str(length, L'\0');
147 if (length > 0) {
148 EXPECT_TRUE(
149 LoggingReadFileExactly(handle, &str[0], length * sizeof(str[0])));
150 }
151 return str;
152}
153
154void WriteWString(FileHandle handle, const std::wstring& str) {
155 size_t length = str.size();
156 EXPECT_TRUE(LoggingWriteFile(handle, &length, sizeof(length)));
157 if (length > 0) {
158 EXPECT_TRUE(LoggingWriteFile(handle, &str[0], length * sizeof(str[0])));
159 }
160}
161
162class TestClient final : public WinChildProcess {
163 public:
164 TestClient() : WinChildProcess() {}
165
166 ~TestClient() {}
167
168 private:
169 int Run() override {
170 std::wstring pipe_name = ReadWString(ReadPipeHandle());
171 CrashpadClient client;
172 if (!client.SetHandlerIPCPipe(pipe_name)) {
173 ADD_FAILURE();
174 return EXIT_FAILURE;
175 }
176 WriteWString(WritePipeHandle(), L"OK");
177 return EXIT_SUCCESS;
178 }
179
180 DISALLOW_COPY_AND_ASSIGN(TestClient);
181};
182
183TEST_F(ExceptionHandlerServerTest, MultipleConnections) {
184 WinChildProcess::EntryPoint<TestClient>();
185
186 std::unique_ptr<WinChildProcess::Handles> handles_1 =
187 WinChildProcess::Launch();
188 std::unique_ptr<WinChildProcess::Handles> handles_2 =
189 WinChildProcess::Launch();
190 std::unique_ptr<WinChildProcess::Handles> handles_3 =
191 WinChildProcess::Launch();
192
193 // Must ensure the delegate outlasts the server.
194 {
195 server_thread().Start();
196 ScopedStopServerAndJoinThread scoped_stop_server_and_join_thread(
197 &server(), &server_thread());
198 ASSERT_NO_FATAL_FAILURE(delegate().WaitForStart());
199
200 // Tell all the children where to connect.
201 WriteWString(handles_1->write.get(), pipe_name());
202 WriteWString(handles_2->write.get(), pipe_name());
203 WriteWString(handles_3->write.get(), pipe_name());
204
205 ASSERT_EQ(ReadWString(handles_3->read.get()), L"OK");
206 ASSERT_EQ(ReadWString(handles_2->read.get()), L"OK");
207 ASSERT_EQ(ReadWString(handles_1->read.get()), L"OK");
208 }
209}
210
211} // namespace
212} // namespace test
213} // namespace crashpad