mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-03-08 09:59:55 +00:00
Fixing Windows client unit tests. They were broken in r1034 due to gMock and
gTest upgrade. While fixing the broken tests I also used the opportunity to add a few more tests that cover filter and callback execution, and nesting of exception handlers. https://breakpad.appspot.com/489002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1073 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
f9a63cb164
commit
df8e3973f4
|
@ -36,8 +36,10 @@
|
||||||
'target_name': 'client_tests',
|
'target_name': 'client_tests',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'sources': [
|
'sources': [
|
||||||
|
'exception_handler_test.h',
|
||||||
'exception_handler_test.cc',
|
'exception_handler_test.cc',
|
||||||
'exception_handler_death_test.cc',
|
'exception_handler_death_test.cc',
|
||||||
|
'exception_handler_nesting_test.cc',
|
||||||
'minidump_test.cc',
|
'minidump_test.cc',
|
||||||
'dump_analysis.cc',
|
'dump_analysis.cc',
|
||||||
'dump_analysis.h',
|
'dump_analysis.h',
|
||||||
|
|
|
@ -31,8 +31,8 @@
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "dump_analysis.h" // NOLINT
|
#include "client/windows/unittests/dump_analysis.h" // NOLINT
|
||||||
#include "gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
DumpAnalysis::~DumpAnalysis() {
|
DumpAnalysis::~DumpAnalysis() {
|
||||||
if (dump_file_view_ != NULL) {
|
if (dump_file_view_ != NULL) {
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#ifndef CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
#ifndef CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||||
#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
#define CLIENT_WINDOWS_UNITTESTS_DUMP_ANALYSIS_H_
|
||||||
|
|
||||||
#include "../crash_generation/minidump_generator.h"
|
#include "client/windows/crash_generation/minidump_generator.h"
|
||||||
|
|
||||||
// Convenience to get to the PEB pointer in a TEB.
|
// Convenience to get to the PEB pointer in a TEB.
|
||||||
struct FakeTEB {
|
struct FakeTEB {
|
||||||
|
|
|
@ -35,11 +35,12 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../../../breakpad_googletest_includes.h"
|
#include "breakpad_googletest_includes.h"
|
||||||
#include "../../../../common/windows/string_utils-inl.h"
|
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||||
#include "../crash_generation/crash_generation_server.h"
|
#include "client/windows/handler/exception_handler.h"
|
||||||
#include "../handler/exception_handler.h"
|
#include "client/windows/unittests/exception_handler_test.h"
|
||||||
#include "../../../../google_breakpad/processor/minidump.h"
|
#include "common/windows/string_utils-inl.h"
|
||||||
|
#include "google_breakpad/processor/minidump.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -122,6 +123,10 @@ TEST_F(ExceptionHandlerDeathTest, InProcTest) {
|
||||||
new google_breakpad::ExceptionHandler(
|
new google_breakpad::ExceptionHandler(
|
||||||
temp_path_, NULL, &MinidumpWrittenCallback, NULL,
|
temp_path_, NULL, &MinidumpWrittenCallback, NULL,
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
int *i = NULL;
|
int *i = NULL;
|
||||||
ASSERT_DEATH((*i)++, kSuccessIndicator);
|
ASSERT_DEATH((*i)++, kSuccessIndicator);
|
||||||
delete exc;
|
delete exc;
|
||||||
|
@ -141,6 +146,10 @@ void ExceptionHandlerDeathTest::DoCrashAccessViolation() {
|
||||||
temp_path_, NULL, NULL, NULL,
|
temp_path_, NULL, NULL, NULL,
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName,
|
google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
// Although this is executing in the child process of the death test,
|
// Although this is executing in the child process of the death test,
|
||||||
// if it's not true we'll still get an error rather than the crash
|
// if it's not true we'll still get an error rather than the crash
|
||||||
// being expected.
|
// being expected.
|
||||||
|
@ -252,6 +261,9 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemory) {
|
||||||
temp_path_, NULL, NULL, NULL,
|
temp_path_, NULL, NULL, NULL,
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
// Get some executable memory.
|
// Get some executable memory.
|
||||||
const u_int32_t kMemorySize = 256; // bytes
|
const u_int32_t kMemorySize = 256; // bytes
|
||||||
const int kOffset = kMemorySize / 2;
|
const int kOffset = kMemorySize / 2;
|
||||||
|
@ -334,6 +346,9 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMinBound) {
|
||||||
temp_path_, NULL, NULL, NULL,
|
temp_path_, NULL, NULL, NULL,
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
SYSTEM_INFO sSysInfo; // Useful information about the system
|
SYSTEM_INFO sSysInfo; // Useful information about the system
|
||||||
GetSystemInfo(&sSysInfo); // Initialize the structure.
|
GetSystemInfo(&sSysInfo); // Initialize the structure.
|
||||||
|
|
||||||
|
@ -421,6 +436,9 @@ TEST_F(ExceptionHandlerDeathTest, InstructionPointerMemoryMaxBound) {
|
||||||
temp_path_, NULL, NULL, NULL,
|
temp_path_, NULL, NULL, NULL,
|
||||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
SYSTEM_INFO sSysInfo; // Useful information about the system
|
SYSTEM_INFO sSysInfo; // Useful information about the system
|
||||||
GetSystemInfo(&sSysInfo); // Initialize the structure.
|
GetSystemInfo(&sSysInfo); // Initialize the structure.
|
||||||
|
|
||||||
|
|
327
src/client/windows/unittests/exception_handler_nesting_test.cc
Executable file
327
src/client/windows/unittests/exception_handler_nesting_test.cc
Executable file
|
@ -0,0 +1,327 @@
|
||||||
|
// Copyright 2012, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "breakpad_googletest_includes.h"
|
||||||
|
#include "client/windows/handler/exception_handler.h"
|
||||||
|
#include "client/windows/unittests/exception_handler_test.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char kFoo[] = "foo";
|
||||||
|
const char kBar[] = "bar";
|
||||||
|
|
||||||
|
const char kStartOfLine[] = "^";
|
||||||
|
const char kEndOfLine[] = "$";
|
||||||
|
|
||||||
|
const char kFilterReturnsTrue[] = "filter_returns_true";
|
||||||
|
const char kFilterReturnsFalse[] = "filter_returns_false";
|
||||||
|
|
||||||
|
const char kCallbackReturnsTrue[] = "callback_returns_true";
|
||||||
|
const char kCallbackReturnsFalse[] = "callback_returns_false";
|
||||||
|
|
||||||
|
bool DoesPathExist(const wchar_t *path_name) {
|
||||||
|
DWORD flags = GetFileAttributes(path_name);
|
||||||
|
if (flags == INVALID_FILE_ATTRIBUTES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A callback function to run before Breakpad performs any substantial
|
||||||
|
// processing of an exception. A FilterCallback is called before writing
|
||||||
|
// a minidump. context is the parameter supplied by the user as
|
||||||
|
// callback_context when the handler was created. exinfo points to the
|
||||||
|
// exception record, if any; assertion points to assertion information,
|
||||||
|
// if any.
|
||||||
|
//
|
||||||
|
// If a FilterCallback returns true, Breakpad will continue processing,
|
||||||
|
// attempting to write a minidump. If a FilterCallback returns false,
|
||||||
|
// Breakpad will immediately report the exception as unhandled without
|
||||||
|
// writing a minidump, allowing another handler the opportunity to handle it.
|
||||||
|
template <bool filter_return_value>
|
||||||
|
bool CrashHandlerFilter(void* context,
|
||||||
|
EXCEPTION_POINTERS* exinfo,
|
||||||
|
MDRawAssertionInfo* assertion) {
|
||||||
|
if (filter_return_value) {
|
||||||
|
fprintf(stderr, kFilterReturnsTrue);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, kFilterReturnsFalse);
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
return filter_return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A callback function to run after the minidump has been written.
|
||||||
|
// minidump_id is a unique id for the dump, so the minidump
|
||||||
|
// file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied
|
||||||
|
// by the user as callback_context when the handler was created. exinfo
|
||||||
|
// points to the exception record, or NULL if no exception occurred.
|
||||||
|
// succeeded indicates whether a minidump file was successfully written.
|
||||||
|
// assertion points to information about an assertion if the handler was
|
||||||
|
// invoked by an assertion.
|
||||||
|
//
|
||||||
|
// If an exception occurred and the callback returns true, Breakpad will treat
|
||||||
|
// the exception as fully-handled, suppressing any other handlers from being
|
||||||
|
// notified of the exception. If the callback returns false, Breakpad will
|
||||||
|
// treat the exception as unhandled, and allow another handler to handle it.
|
||||||
|
// If there are no other handlers, Breakpad will report the exception to the
|
||||||
|
// system as unhandled, allowing a debugger or native crash dialog the
|
||||||
|
// opportunity to handle the exception. Most callback implementations
|
||||||
|
// should normally return the value of |succeeded|, or when they wish to
|
||||||
|
// not report an exception of handled, false. Callbacks will rarely want to
|
||||||
|
// return true directly (unless |succeeded| is true).
|
||||||
|
//
|
||||||
|
// For out-of-process dump generation, dump path and minidump ID will always
|
||||||
|
// be NULL. In case of out-of-process dump generation, the dump path and
|
||||||
|
// minidump id are controlled by the server process and are not communicated
|
||||||
|
// back to the crashing process.
|
||||||
|
template <bool callback_return_value>
|
||||||
|
bool MinidumpWrittenCallback(const wchar_t* dump_path,
|
||||||
|
const wchar_t* minidump_id,
|
||||||
|
void* context,
|
||||||
|
EXCEPTION_POINTERS* exinfo,
|
||||||
|
MDRawAssertionInfo* assertion,
|
||||||
|
bool succeeded) {
|
||||||
|
bool rv = false;
|
||||||
|
if (callback_return_value &&
|
||||||
|
succeeded &&
|
||||||
|
DoesPathExist(dump_path)) {
|
||||||
|
rv = true;
|
||||||
|
fprintf(stderr, kCallbackReturnsTrue);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, kCallbackReturnsFalse);
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DoCrash(const char *message) {
|
||||||
|
if (message) {
|
||||||
|
fprintf(stderr, "%s", message);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
int *i = NULL;
|
||||||
|
(*i)++;
|
||||||
|
|
||||||
|
ASSERT_TRUE(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstallExceptionHandlerAndCrash(bool install_filter,
|
||||||
|
bool filter_return_value,
|
||||||
|
bool install_callback,
|
||||||
|
bool callback_return_value) {
|
||||||
|
wchar_t temp_path[MAX_PATH] = { '\0' };
|
||||||
|
GetTempPath(MAX_PATH, temp_path);
|
||||||
|
|
||||||
|
ASSERT_TRUE(DoesPathExist(temp_path));
|
||||||
|
google_breakpad::ExceptionHandler exc(
|
||||||
|
temp_path,
|
||||||
|
install_filter ?
|
||||||
|
(filter_return_value ?
|
||||||
|
&CrashHandlerFilter<true> :
|
||||||
|
&CrashHandlerFilter<false>) :
|
||||||
|
NULL,
|
||||||
|
install_callback ?
|
||||||
|
(callback_return_value ?
|
||||||
|
&MinidumpWrittenCallback<true> :
|
||||||
|
&MinidumpWrittenCallback<false>) :
|
||||||
|
NULL,
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_EXCEPTION);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
|
DoCrash(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AssertDeathSanity, Simple) {
|
||||||
|
ASSERT_DEATH(DoCrash(NULL), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AssertDeathSanity, Regex) {
|
||||||
|
ASSERT_DEATH(DoCrash(kFoo),
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFoo) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
|
||||||
|
ASSERT_DEATH(DoCrash(kBar),
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kBar) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerCallbacks, FilterTrue_No_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
false, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsTrue) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerCallbacks, FilterTrue_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsTrue) +
|
||||||
|
std::string(kCallbackReturnsFalse) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerCallbacks, FilterFalse_No_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
false, // filter_return_value
|
||||||
|
false, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsFalse) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback shouldn't be executed when filter returns false
|
||||||
|
TEST(ExceptionHandlerCallbacks, FilterFalse_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
false, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsFalse) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerCallbacks, No_Filter_No_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(false, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
false, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerCallbacks, No_Filter_Callback) {
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(false, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kCallbackReturnsFalse) +
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerNesting, Skip_From_Inner_Filter) {
|
||||||
|
wchar_t temp_path[MAX_PATH] = { '\0' };
|
||||||
|
GetTempPath(MAX_PATH, temp_path);
|
||||||
|
|
||||||
|
ASSERT_TRUE(DoesPathExist(temp_path));
|
||||||
|
google_breakpad::ExceptionHandler exc(
|
||||||
|
temp_path,
|
||||||
|
&CrashHandlerFilter<true>,
|
||||||
|
&MinidumpWrittenCallback<false>,
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_EXCEPTION);
|
||||||
|
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
false, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
true), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsFalse) + // inner filter
|
||||||
|
std::string(kFilterReturnsTrue) + // outer filter
|
||||||
|
std::string(kCallbackReturnsFalse) + // outer callback
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerNesting, Skip_From_Inner_Callback) {
|
||||||
|
wchar_t temp_path[MAX_PATH] = { '\0' };
|
||||||
|
GetTempPath(MAX_PATH, temp_path);
|
||||||
|
|
||||||
|
ASSERT_TRUE(DoesPathExist(temp_path));
|
||||||
|
google_breakpad::ExceptionHandler exc(
|
||||||
|
temp_path,
|
||||||
|
&CrashHandlerFilter<true>,
|
||||||
|
&MinidumpWrittenCallback<false>,
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_EXCEPTION);
|
||||||
|
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
false), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsTrue) + // inner filter
|
||||||
|
std::string(kCallbackReturnsFalse) + // inner callback
|
||||||
|
std::string(kFilterReturnsTrue) + // outer filter
|
||||||
|
std::string(kCallbackReturnsFalse) + // outer callback
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ExceptionHandlerNesting, Handled_By_Inner_Handler) {
|
||||||
|
wchar_t temp_path[MAX_PATH] = { '\0' };
|
||||||
|
GetTempPath(MAX_PATH, temp_path);
|
||||||
|
|
||||||
|
ASSERT_TRUE(DoesPathExist(temp_path));
|
||||||
|
google_breakpad::ExceptionHandler exc(
|
||||||
|
temp_path,
|
||||||
|
&CrashHandlerFilter<true>,
|
||||||
|
&MinidumpWrittenCallback<true>,
|
||||||
|
NULL, // callback_context
|
||||||
|
google_breakpad::ExceptionHandler::HANDLER_EXCEPTION);
|
||||||
|
|
||||||
|
ASSERT_DEATH(
|
||||||
|
InstallExceptionHandlerAndCrash(true, // install_filter
|
||||||
|
true, // filter_return_value
|
||||||
|
true, // install_callback
|
||||||
|
true), // callback_return_value
|
||||||
|
std::string(kStartOfLine) +
|
||||||
|
std::string(kFilterReturnsTrue) + // inner filter
|
||||||
|
std::string(kCallbackReturnsTrue) + // inner callback
|
||||||
|
std::string(kEndOfLine));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
|
@ -27,6 +27,8 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "client/windows/unittests/exception_handler_test.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#include <strsafe.h>
|
#include <strsafe.h>
|
||||||
|
@ -35,12 +37,25 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../../../breakpad_googletest_includes.h"
|
#include "breakpad_googletest_includes.h"
|
||||||
#include "../../../../common/windows/string_utils-inl.h"
|
#include "client/windows/crash_generation/crash_generation_server.h"
|
||||||
#include "../../../../google_breakpad/processor/minidump.h"
|
#include "client/windows/handler/exception_handler.h"
|
||||||
#include "../crash_generation/crash_generation_server.h"
|
#include "client/windows/unittests/dump_analysis.h" // NOLINT
|
||||||
#include "../handler/exception_handler.h"
|
#include "common/windows/string_utils-inl.h"
|
||||||
#include "dump_analysis.h" // NOLINT
|
#include "google_breakpad/processor/minidump.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
DisableExceptionHandlerInScope::DisableExceptionHandlerInScope() {
|
||||||
|
catch_exceptions_ = GTEST_FLAG(catch_exceptions);
|
||||||
|
GTEST_FLAG(catch_exceptions) = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisableExceptionHandlerInScope::~DisableExceptionHandlerInScope() {
|
||||||
|
GTEST_FLAG(catch_exceptions) = catch_exceptions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -361,6 +376,10 @@ TEST_F(ExceptionHandlerTest, WriteMinidumpTest) {
|
||||||
DumpCallback,
|
DumpCallback,
|
||||||
NULL,
|
NULL,
|
||||||
ExceptionHandler::HANDLER_ALL);
|
ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
ASSERT_TRUE(handler.WriteMinidump());
|
ASSERT_TRUE(handler.WriteMinidump());
|
||||||
ASSERT_FALSE(dump_file.empty());
|
ASSERT_FALSE(dump_file.empty());
|
||||||
|
|
||||||
|
@ -396,6 +415,9 @@ TEST_F(ExceptionHandlerTest, AdditionalMemory) {
|
||||||
NULL,
|
NULL,
|
||||||
ExceptionHandler::HANDLER_ALL);
|
ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
// Add the memory region to the list of memory to be included.
|
// Add the memory region to the list of memory to be included.
|
||||||
handler.RegisterAppMemory(memory, kMemorySize);
|
handler.RegisterAppMemory(memory, kMemorySize);
|
||||||
ASSERT_TRUE(handler.WriteMinidump());
|
ASSERT_TRUE(handler.WriteMinidump());
|
||||||
|
@ -447,6 +469,9 @@ TEST_F(ExceptionHandlerTest, AdditionalMemoryRemove) {
|
||||||
NULL,
|
NULL,
|
||||||
ExceptionHandler::HANDLER_ALL);
|
ExceptionHandler::HANDLER_ALL);
|
||||||
|
|
||||||
|
// Disable GTest SEH handler
|
||||||
|
testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
|
||||||
// Add the memory region to the list of memory to be included.
|
// Add the memory region to the list of memory to be included.
|
||||||
handler.RegisterAppMemory(memory, kMemorySize);
|
handler.RegisterAppMemory(memory, kMemorySize);
|
||||||
|
|
||||||
|
|
61
src/client/windows/unittests/exception_handler_test.h
Executable file
61
src/client/windows/unittests/exception_handler_test.h
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2012, Google Inc.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#ifndef CLIENT_WINDOWS_UNITTESTS_EXCEPTION_HANDLER_TEST_H_
|
||||||
|
#define CLIENT_WINDOWS_UNITTESTS_EXCEPTION_HANDLER_TEST_H_
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// By default, GTest (on Windows) installs a SEH filter (and a handler) before
|
||||||
|
// starting to run all the tests in order to avoid test interruptions is some
|
||||||
|
// of the tests are crashing. Unfortunately, this functionality prevents the
|
||||||
|
// execution to reach the UnhandledExceptionFilter installed by Google-Breakpad
|
||||||
|
// ExceptionHandler so in order to test the Google-Breakpad exception handling
|
||||||
|
// code the exception handling done by GTest must be disabled.
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// google_breakpad::ExceptionHandler exc(...);
|
||||||
|
//
|
||||||
|
// // Disable GTest SEH handler
|
||||||
|
// testing::DisableExceptionHandlerInScope disable_exception_handler;
|
||||||
|
// ...
|
||||||
|
// ASSERT_DEATH( ... some crash ...);
|
||||||
|
//
|
||||||
|
class DisableExceptionHandlerInScope {
|
||||||
|
public:
|
||||||
|
DisableExceptionHandlerInScope();
|
||||||
|
~DisableExceptionHandlerInScope();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool catch_exceptions_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // CLIENT_WINDOWS_UNITTESTS_EXCEPTION_HANDLER_TEST_H_
|
|
@ -31,8 +31,8 @@
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
#include "../crash_generation/minidump_generator.h"
|
#include "client/windows/crash_generation/minidump_generator.h"
|
||||||
#include "dump_analysis.h" // NOLINT
|
#include "client/windows/unittests/dump_analysis.h" // NOLINT
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue