mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 15:15:37 +00:00
Allow option for efficient and safe opt out of in-proc dump generation for Windows breakpad clients.
https://breakpad.appspot.com/549002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1157 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
697da828dc
commit
40c9de4d8d
|
@ -178,6 +178,10 @@ CrashGenerationClient::~CrashGenerationClient() {
|
||||||
//
|
//
|
||||||
// Returns true if the registration is successful; false otherwise.
|
// Returns true if the registration is successful; false otherwise.
|
||||||
bool CrashGenerationClient::Register() {
|
bool CrashGenerationClient::Register() {
|
||||||
|
if (IsRegistered()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
HANDLE pipe = ConnectToServer();
|
HANDLE pipe = ConnectToServer();
|
||||||
if (!pipe) {
|
if (!pipe) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -73,7 +73,8 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path,
|
||||||
handler_types,
|
handler_types,
|
||||||
dump_type,
|
dump_type,
|
||||||
pipe_name,
|
pipe_name,
|
||||||
NULL,
|
NULL, // pipe_handle
|
||||||
|
NULL, // crash_generation_client
|
||||||
custom_info);
|
custom_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +92,30 @@ ExceptionHandler::ExceptionHandler(const wstring& dump_path,
|
||||||
callback_context,
|
callback_context,
|
||||||
handler_types,
|
handler_types,
|
||||||
dump_type,
|
dump_type,
|
||||||
NULL,
|
NULL, // pipe_name
|
||||||
pipe_handle,
|
pipe_handle,
|
||||||
|
NULL, // crash_generation_client
|
||||||
|
custom_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExceptionHandler::ExceptionHandler(
|
||||||
|
const wstring& dump_path,
|
||||||
|
FilterCallback filter,
|
||||||
|
MinidumpCallback callback,
|
||||||
|
void* callback_context,
|
||||||
|
int handler_types,
|
||||||
|
MINIDUMP_TYPE dump_type,
|
||||||
|
CrashGenerationClient* crash_generation_client,
|
||||||
|
const CustomClientInfo* custom_info) {
|
||||||
|
Initialize(dump_path,
|
||||||
|
filter,
|
||||||
|
callback,
|
||||||
|
callback_context,
|
||||||
|
handler_types,
|
||||||
|
MiniDumpNormal,
|
||||||
|
NULL, // pipe_name
|
||||||
|
NULL, // pipe_handle
|
||||||
|
crash_generation_client,
|
||||||
custom_info);
|
custom_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,20 +130,23 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path,
|
||||||
callback_context,
|
callback_context,
|
||||||
handler_types,
|
handler_types,
|
||||||
MiniDumpNormal,
|
MiniDumpNormal,
|
||||||
NULL,
|
NULL, // pipe_name
|
||||||
NULL,
|
NULL, // pipe_handle
|
||||||
NULL);
|
NULL, // crash_generation_client
|
||||||
|
NULL); // custom_info
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionHandler::Initialize(const wstring& dump_path,
|
void ExceptionHandler::Initialize(
|
||||||
FilterCallback filter,
|
const wstring& dump_path,
|
||||||
MinidumpCallback callback,
|
FilterCallback filter,
|
||||||
void* callback_context,
|
MinidumpCallback callback,
|
||||||
int handler_types,
|
void* callback_context,
|
||||||
MINIDUMP_TYPE dump_type,
|
int handler_types,
|
||||||
const wchar_t* pipe_name,
|
MINIDUMP_TYPE dump_type,
|
||||||
HANDLE pipe_handle,
|
const wchar_t* pipe_name,
|
||||||
const CustomClientInfo* custom_info) {
|
HANDLE pipe_handle,
|
||||||
|
CrashGenerationClient* crash_generation_client,
|
||||||
|
const CustomClientInfo* custom_info) {
|
||||||
LONG instance_count = InterlockedIncrement(&instance_count_);
|
LONG instance_count = InterlockedIncrement(&instance_count_);
|
||||||
filter_ = filter;
|
filter_ = filter;
|
||||||
callback_ = callback;
|
callback_ = callback;
|
||||||
|
@ -149,23 +175,20 @@ void ExceptionHandler::Initialize(const wstring& dump_path,
|
||||||
handler_return_value_ = false;
|
handler_return_value_ = false;
|
||||||
handle_debug_exceptions_ = false;
|
handle_debug_exceptions_ = false;
|
||||||
|
|
||||||
// Attempt to use out-of-process if user has specified a pipe.
|
// Attempt to use out-of-process if user has specified a pipe or a
|
||||||
if (pipe_name != NULL || pipe_handle != NULL) {
|
// crash generation client.
|
||||||
assert(!(pipe_name && pipe_handle));
|
scoped_ptr<CrashGenerationClient> client;
|
||||||
|
if (crash_generation_client) {
|
||||||
scoped_ptr<CrashGenerationClient> client;
|
client.reset(crash_generation_client);
|
||||||
if (pipe_name) {
|
} else if (pipe_name) {
|
||||||
client.reset(
|
client.reset(
|
||||||
new CrashGenerationClient(pipe_name,
|
new CrashGenerationClient(pipe_name, dump_type_, custom_info));
|
||||||
dump_type_,
|
} else if (pipe_handle) {
|
||||||
custom_info));
|
client.reset(
|
||||||
} else {
|
new CrashGenerationClient(pipe_handle, dump_type_, custom_info));
|
||||||
client.reset(
|
}
|
||||||
new CrashGenerationClient(pipe_handle,
|
|
||||||
dump_type_,
|
|
||||||
custom_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (client.get() != NULL) {
|
||||||
// If successful in registering with the monitoring process,
|
// If successful in registering with the monitoring process,
|
||||||
// there is no need to setup in-process crash generation.
|
// there is no need to setup in-process crash generation.
|
||||||
if (client->Register()) {
|
if (client->Register()) {
|
||||||
|
|
|
@ -195,6 +195,27 @@ class ExceptionHandler {
|
||||||
HANDLE pipe_handle,
|
HANDLE pipe_handle,
|
||||||
const CustomClientInfo* custom_info);
|
const CustomClientInfo* custom_info);
|
||||||
|
|
||||||
|
// ExceptionHandler that ENSURES out-of-process dump generation. Expects a
|
||||||
|
// crash generation client that is already registered with a crash generation
|
||||||
|
// server. Takes ownership of the passed-in crash_generation_client.
|
||||||
|
//
|
||||||
|
// Usage example:
|
||||||
|
// crash_generation_client = new CrashGenerationClient(..);
|
||||||
|
// if (crash_generation_client->Register()) {
|
||||||
|
// // Registration with the crash generation server succeeded.
|
||||||
|
// // Out-of-process dump generation is guaranteed.
|
||||||
|
// g_handler = new ExceptionHandler(.., crash_generation_client, ..);
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
ExceptionHandler(const wstring& dump_path,
|
||||||
|
FilterCallback filter,
|
||||||
|
MinidumpCallback callback,
|
||||||
|
void* callback_context,
|
||||||
|
int handler_types,
|
||||||
|
MINIDUMP_TYPE dump_type,
|
||||||
|
CrashGenerationClient* crash_generation_client,
|
||||||
|
const CustomClientInfo* custom_info);
|
||||||
|
|
||||||
~ExceptionHandler();
|
~ExceptionHandler();
|
||||||
|
|
||||||
// Get and set the minidump path.
|
// Get and set the minidump path.
|
||||||
|
@ -264,6 +285,7 @@ class ExceptionHandler {
|
||||||
MINIDUMP_TYPE dump_type,
|
MINIDUMP_TYPE dump_type,
|
||||||
const wchar_t* pipe_name,
|
const wchar_t* pipe_name,
|
||||||
HANDLE pipe_handle,
|
HANDLE pipe_handle,
|
||||||
|
CrashGenerationClient* crash_generation_client,
|
||||||
const CustomClientInfo* custom_info);
|
const CustomClientInfo* custom_info);
|
||||||
|
|
||||||
// Function pointer type for MiniDumpWriteDump, which is looked up
|
// Function pointer type for MiniDumpWriteDump, which is looked up
|
||||||
|
|
|
@ -54,6 +54,11 @@ const char kFailureIndicator[] = "failure";
|
||||||
// Utility function to test for a path's existence.
|
// Utility function to test for a path's existence.
|
||||||
BOOL DoesPathExist(const TCHAR *path_name);
|
BOOL DoesPathExist(const TCHAR *path_name);
|
||||||
|
|
||||||
|
enum OutOfProcGuarantee {
|
||||||
|
OUT_OF_PROC_GUARANTEED,
|
||||||
|
OUT_OF_PROC_BEST_EFFORT,
|
||||||
|
};
|
||||||
|
|
||||||
class ExceptionHandlerDeathTest : public ::testing::Test {
|
class ExceptionHandlerDeathTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
// Member variable for each test that they can use
|
// Member variable for each test that they can use
|
||||||
|
@ -62,7 +67,7 @@ class ExceptionHandlerDeathTest : public ::testing::Test {
|
||||||
// Actually constructs a temp path name.
|
// Actually constructs a temp path name.
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
// A helper method that tests can use to crash.
|
// A helper method that tests can use to crash.
|
||||||
void DoCrashAccessViolation();
|
void DoCrashAccessViolation(const OutOfProcGuarantee out_of_proc_guarantee);
|
||||||
void DoCrashPureVirtualCall();
|
void DoCrashPureVirtualCall();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,12 +145,37 @@ void clientDumpCallback(void *dump_context,
|
||||||
gDumpCallbackCalled = true;
|
gDumpCallbackCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionHandlerDeathTest::DoCrashAccessViolation() {
|
void ExceptionHandlerDeathTest::DoCrashAccessViolation(
|
||||||
google_breakpad::ExceptionHandler *exc =
|
const OutOfProcGuarantee out_of_proc_guarantee) {
|
||||||
new google_breakpad::ExceptionHandler(
|
google_breakpad::ExceptionHandler *exc = NULL;
|
||||||
temp_path_, NULL, NULL, NULL,
|
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName,
|
if (out_of_proc_guarantee == OUT_OF_PROC_GUARANTEED) {
|
||||||
NULL);
|
google_breakpad::CrashGenerationClient *client =
|
||||||
|
new google_breakpad::CrashGenerationClient(kPipeName,
|
||||||
|
MiniDumpNormal,
|
||||||
|
NULL); // custom_info
|
||||||
|
ASSERT_TRUE(client->Register());
|
||||||
|
exc = new google_breakpad::ExceptionHandler(
|
||||||
|
temp_path_,
|
||||||
|
NULL, // filter
|
||||||
|
NULL, // callback
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||||
|
MiniDumpNormal,
|
||||||
|
client,
|
||||||
|
NULL); // custom_info
|
||||||
|
} else {
|
||||||
|
ASSERT_TRUE(out_of_proc_guarantee == OUT_OF_PROC_BEST_EFFORT);
|
||||||
|
exc = new google_breakpad::ExceptionHandler(
|
||||||
|
temp_path_,
|
||||||
|
NULL, // filter
|
||||||
|
NULL, // callback
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_ALL,
|
||||||
|
MiniDumpNormal,
|
||||||
|
kPipeName,
|
||||||
|
NULL); // custom_info
|
||||||
|
}
|
||||||
|
|
||||||
// Disable GTest SEH handler
|
// Disable GTest SEH handler
|
||||||
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
@ -170,15 +200,38 @@ TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) {
|
||||||
ASSERT_TRUE(DoesPathExist(temp_path_));
|
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||||
std::wstring dump_path(temp_path_);
|
std::wstring dump_path(temp_path_);
|
||||||
google_breakpad::CrashGenerationServer server(
|
google_breakpad::CrashGenerationServer server(
|
||||||
kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL,
|
kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL,
|
||||||
NULL, true, &dump_path);
|
NULL, true, &dump_path);
|
||||||
|
|
||||||
// This HAS to be EXPECT_, because when this test case is executed in the
|
// This HAS to be EXPECT_, because when this test case is executed in the
|
||||||
// child process, the server registration will fail due to the named pipe
|
// child process, the server registration will fail due to the named pipe
|
||||||
// being the same.
|
// being the same.
|
||||||
EXPECT_TRUE(server.Start());
|
EXPECT_TRUE(server.Start());
|
||||||
EXPECT_FALSE(gDumpCallbackCalled);
|
gDumpCallbackCalled = false;
|
||||||
ASSERT_DEATH(this->DoCrashAccessViolation(), "");
|
ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_BEST_EFFORT), "");
|
||||||
|
EXPECT_TRUE(gDumpCallbackCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ExceptionHandlerDeathTest, OutOfProcGuaranteedTest) {
|
||||||
|
// This is similar to the previous test (OutOfProcTest). The only difference
|
||||||
|
// is that in this test, the crash generation client is created and registered
|
||||||
|
// with the crash generation server outside of the ExceptionHandler
|
||||||
|
// constructor which allows breakpad users to opt out of the default
|
||||||
|
// in-process dump generation when the registration with the crash generation
|
||||||
|
// server fails.
|
||||||
|
|
||||||
|
ASSERT_TRUE(DoesPathExist(temp_path_));
|
||||||
|
std::wstring dump_path(temp_path_);
|
||||||
|
google_breakpad::CrashGenerationServer server(
|
||||||
|
kPipeName, NULL, NULL, NULL, &clientDumpCallback, NULL, NULL, NULL, NULL,
|
||||||
|
NULL, true, &dump_path);
|
||||||
|
|
||||||
|
// This HAS to be EXPECT_, because when this test case is executed in the
|
||||||
|
// child process, the server registration will fail due to the named pipe
|
||||||
|
// being the same.
|
||||||
|
EXPECT_TRUE(server.Start());
|
||||||
|
gDumpCallbackCalled = false;
|
||||||
|
ASSERT_DEATH(this->DoCrashAccessViolation(OUT_OF_PROC_GUARANTEED), "");
|
||||||
EXPECT_TRUE(gDumpCallbackCalled);
|
EXPECT_TRUE(gDumpCallbackCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue