diff options
3 files changed, 440 insertions, 0 deletions
diff --git a/src/client/windows/breakpad_client.sln b/src/client/windows/breakpad_client.sln index 8c9c02b2..d938a374 100644 --- a/src/client/windows/breakpad_client.sln +++ b/src/client/windows/breakpad_client.sln @@ -10,6 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_report_sender", "send EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crash_generation", "crash_generation\crash_generation.vcproj", "{A820AF62-6239-4693-8430-4F516C1838F4}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exception_handler_test", "handler\exception_handler_test\exception_handler_test.vcproj", "{89094A11-CF25-4037-AF43-EACFA751405E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -42,6 +44,14 @@ Global {A820AF62-6239-4693-8430-4F516C1838F4}.Release|Win32.Build.0 = Release|Win32 {A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.ActiveCfg = ReleaseStaticCRT|Win32 {A820AF62-6239-4693-8430-4F516C1838F4}.ReleaseStaticCRT|Win32.Build.0 = ReleaseStaticCRT|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.Debug|Win32.ActiveCfg = Debug|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.Debug|Win32.Build.0 = Debug|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.DebugStaticCRT|Win32.ActiveCfg = Debug|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.DebugStaticCRT|Win32.Build.0 = Debug|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.Release|Win32.ActiveCfg = Release|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.Release|Win32.Build.0 = Release|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.ReleaseStaticCRT|Win32.ActiveCfg = Release|Win32 + {89094A11-CF25-4037-AF43-EACFA751405E}.ReleaseStaticCRT|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/client/windows/handler/exception_handler_test/exception_handler_test.cc b/src/client/windows/handler/exception_handler_test/exception_handler_test.cc new file mode 100644 index 00000000..2b7377ea --- /dev/null +++ b/src/client/windows/handler/exception_handler_test/exception_handler_test.cc @@ -0,0 +1,164 @@ +// Copyright 2009, 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 "breakpad_googletest_includes.h" +#include "client/windows/crash_generation/crash_generation_server.h" +#include "client/windows/handler/exception_handler.h" +#include <windows.h> +#include <dbghelp.h> +#include <strsafe.h> +#include <objbase.h> +#include <shellapi.h> + +namespace { +const wchar_t kPipeName[] = L"\\\\.\\pipe\\BreakpadCrashTest\\TestCaseServer"; +const char kSuccessIndicator[] = "success"; +const char kFailureIndicator[] = "failure"; + +// Utility function to test for a path's existence. +BOOL DoesPathExist(const TCHAR *path_name); + +class ExceptionHandlerDeathTest : public ::testing::Test { +protected: + // Member variable for each test that they can use + // for temporary storage. + TCHAR temp_path_[MAX_PATH]; + // Actually constructs a temp path name. + virtual void SetUp(); + // A helper method that tests can use to crash. + void DoCrash(); +}; + +void ExceptionHandlerDeathTest::SetUp() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + TCHAR temp_path[MAX_PATH] = { '\0' }; + TCHAR test_name_wide[MAX_PATH] = { '\0' }; + // We want the temporary directory to be what the OS returns + // to us, + the test case name. + GetTempPath(MAX_PATH, temp_path); + // THe test case name is exposed to use as a c-style string, + // But we might be working in UNICODE here on Windows. + int dwRet = MultiByteToWideChar(CP_ACP, 0, test_info->name(), + (int)strlen(test_info->name()), test_name_wide, MAX_PATH); + if (!dwRet) { + assert(false); + } + StringCchPrintfW(temp_path_, MAX_PATH, L"%s%s", temp_path, test_name_wide); + CreateDirectory(temp_path_, NULL); +} + +BOOL DoesPathExist(const TCHAR *path_name) { + DWORD flags = GetFileAttributes(path_name); + if (flags == INVALID_FILE_ATTRIBUTES) { + return FALSE; + } + return TRUE; +} + +bool MinidumpWrittenCallback(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, + bool succeeded) { + if (succeeded && DoesPathExist(dump_path)) { + fprintf(stderr, kSuccessIndicator); + } else { + fprintf(stderr, kFailureIndicator); + } + // If we don't flush, the output doesn't get sent before + // this process dies. + fflush(stderr); + return succeeded; +} + +TEST_F(ExceptionHandlerDeathTest, InProcTest) { + // For the in-proc test, we just need to instantiate an exception + // handler in in-proc mode, and crash. Since the entire test is + // reexecuted in the child process, we don't have to worry about + // the semantics of the exception handler being inherited/not + // inherited across CreateProcess(). + ASSERT_TRUE(DoesPathExist(temp_path_)); + google_breakpad::ExceptionHandler *exc = + new google_breakpad::ExceptionHandler( + temp_path_, NULL, &MinidumpWrittenCallback, NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL); + int *i = NULL; + ASSERT_DEATH((*i)++, kSuccessIndicator); + delete exc; +} + +static bool gDumpCallbackCalled = false; + +void clientDumpCallback(void *dump_context, + const google_breakpad::ClientInfo *client_info, + const std::wstring *dump_path){ + + gDumpCallbackCalled = true; +} + +void ExceptionHandlerDeathTest::DoCrash() { + google_breakpad::ExceptionHandler *exc = + new google_breakpad::ExceptionHandler( + temp_path_, NULL, NULL, NULL, + google_breakpad::ExceptionHandler::HANDLER_ALL, MiniDumpNormal, kPipeName, + NULL); + // 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 + // being expected. + ASSERT_TRUE(exc->IsOutOfProcess()); + int *i = NULL; + printf("%d\n", (*i)++); +} + +TEST_F(ExceptionHandlerDeathTest, OutOfProcTest) { + // We can take advantage of a detail of google test here to save some + // complexity in testing: when you do a death test, it actually forks. + // So we can make the main test harness the crash generation server, + // and call ASSERT_DEATH on a NULL dereference, it to expecting test + // the out of process scenario, since it's happening in a different + // process! This is different from the above because, above, we pass + // a NULL pipe name, and we also don't start a crash generation server. + + ASSERT_TRUE(DoesPathExist(temp_path_)); + std::wstring dump_path(temp_path_); + google_breakpad::CrashGenerationServer server( + kPipeName, NULL, NULL, NULL, &clientDumpCallback, 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()); + EXPECT_FALSE(gDumpCallbackCalled); + ASSERT_DEATH(this->DoCrash(), ""); + EXPECT_TRUE(gDumpCallbackCalled); +} +}
\ No newline at end of file diff --git a/src/client/windows/handler/exception_handler_test/exception_handler_test.vcproj b/src/client/windows/handler/exception_handler_test/exception_handler_test.vcproj new file mode 100644 index 00000000..4708d88e --- /dev/null +++ b/src/client/windows/handler/exception_handler_test/exception_handler_test.vcproj @@ -0,0 +1,266 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="exception_handler_test" + ProjectGUID="{89094A11-CF25-4037-AF43-EACFA751405E}" + RootNamespace="exception_handler_test" + Keyword="Win32Proj" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + Description="" + CommandLine="" + Outputs="" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="..\..\..\..\testing;..\..\..\..\testing\include;..\..\..\..\testing\gtest;..\..\..\..\testing\gtest\include;..\..\..\..\" + PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="2" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + Description="Running tests" + CommandLine="$(OutDir)\$(ProjectName).exe" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories="..\..\..\..\testing;..\..\..\..\testing\include;..\..\..\..\testing\gtest;..\..\..\..\testing\gtest\include;..\..\..\..\" + PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_WIN32_WINNT=0x0500" + RuntimeLibrary="2" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCWebDeploymentTool" + /> + <Tool + Name="VCPostBuildEventTool" + Description="Running tests" + CommandLine="$(OutDir)\$(ProjectName).exe" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath="..\..\crash_generation\client_info.cc" + > + </File> + <File + RelativePath="..\..\crash_generation\crash_generation_client.cc" + > + </File> + <File + RelativePath="..\..\crash_generation\crash_generation_server.cc" + > + </File> + <File + RelativePath="..\exception_handler.cc" + > + </File> + <File + RelativePath=".\exception_handler_test.cc" + > + </File> + <File + RelativePath="..\..\..\..\testing\gtest\src\gtest-all.cc" + > + </File> + <File + RelativePath="..\..\..\..\testing\gtest\src\gtest_main.cc" + > + </File> + <File + RelativePath="..\..\..\..\common\windows\guid_string.cc" + > + </File> + <File + RelativePath="..\..\crash_generation\minidump_generator.cc" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath="..\..\crash_generation\client_info.h" + > + </File> + <File + RelativePath="..\..\crash_generation\crash_generation_client.h" + > + </File> + <File + RelativePath="..\..\crash_generation\crash_generation_server.h" + > + </File> + <File + RelativePath="..\exception_handler.h" + > + </File> + <File + RelativePath="..\..\..\..\common\windows\guid_string.h" + > + </File> + <File + RelativePath="..\..\crash_generation\minidump_generator.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <File + RelativePath=".\ReadMe.txt" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> |