This fixes the crashes happens from V8 not caught by the crash reporter,
for more context, see http://code.google.com/p/v8/issues/detail?id=3597.

Fix #2365.
This commit is contained in:
Cheng Zhao 2015-10-15 14:16:27 +08:00
Родитель 55d5660ddb
Коммит d90b598125
3 изменённых файлов: 135 добавлений и 3 удалений

Просмотреть файл

@ -19,6 +19,10 @@
#include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h"
#if defined(OS_WIN)
#include "atom/common/crash_reporter/crash_reporter_win.h"
#endif
namespace atom {
namespace {
@ -69,6 +73,10 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
// Logging with pid and timestamp.
logging::SetLogItems(true, false, true, false);
#if defined(OS_WIN)
crash_reporter::SetupV8CodeRangeHook();
#endif
#if defined(DEBUG) && defined(OS_LINUX)
// Enable convient stack printing.
base::debug::EnableInProcessStackDumping();

Просмотреть файл

@ -11,6 +11,25 @@
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/result_codes.h"
#include "gin/public/debug.h"
#include "sandbox/win/src/nt_internals.h"
#pragma intrinsic(_AddressOfReturnAddress)
#pragma intrinsic(_ReturnAddress)
#ifdef _WIN64
// See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
typedef struct _UNWIND_INFO {
unsigned char Version : 3;
unsigned char Flags : 5;
unsigned char SizeOfProlog;
unsigned char CountOfCodes;
unsigned char FrameRegister : 4;
unsigned char FrameOffset : 4;
ULONG ExceptionHandler;
} UNWIND_INFO, *PUNWIND_INFO;
#endif
namespace crash_reporter {
@ -24,8 +43,101 @@ const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
const wchar_t kWaitEventFormat[] = L"$1CrashServiceWaitEvent";
const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\$1 Crash Service";
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
NTSTATUS ExitStatus);
char* g_real_terminate_process_stub = NULL;
void TerminateProcessWithoutDump() {
// Patched stub exists based on conditions (See InitCrashReporter).
// As a side note this function also gets called from
// WindowProcExceptionFilter.
if (g_real_terminate_process_stub == NULL) {
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
} else {
NtTerminateProcessPtr real_terminate_proc =
reinterpret_cast<NtTerminateProcessPtr>(
static_cast<char*>(g_real_terminate_process_stub));
real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
}
}
#ifdef _WIN64
int CrashForExceptionInNonABICompliantCodeRange(
PEXCEPTION_RECORD ExceptionRecord,
ULONG64 EstablisherFrame,
PCONTEXT ContextRecord,
PDISPATCHER_CONTEXT DispatcherContext) {
EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord };
if (!CrashReporter::GetInstance())
return EXCEPTION_CONTINUE_SEARCH;
return static_cast<CrashReporterWin*>(CrashReporter::GetInstance())->
CrashForException(&info);
}
struct ExceptionHandlerRecord {
RUNTIME_FUNCTION runtime_function;
UNWIND_INFO unwind_info;
unsigned char thunk[12];
};
void RegisterNonABICompliantCodeRange(void* start, size_t size_in_bytes) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
// We assume that the first page of the code range is executable and
// committed and reserved for breakpad. What could possibly go wrong?
// All addresses are 32bit relative offsets to start.
record->runtime_function.BeginAddress = 0;
record->runtime_function.EndAddress =
base::checked_cast<DWORD>(size_in_bytes);
record->runtime_function.UnwindData =
offsetof(ExceptionHandlerRecord, unwind_info);
// Create unwind info that only specifies an exception handler.
record->unwind_info.Version = 1;
record->unwind_info.Flags = UNW_FLAG_EHANDLER;
record->unwind_info.SizeOfProlog = 0;
record->unwind_info.CountOfCodes = 0;
record->unwind_info.FrameRegister = 0;
record->unwind_info.FrameOffset = 0;
record->unwind_info.ExceptionHandler =
offsetof(ExceptionHandlerRecord, thunk);
// Hardcoded thunk.
// mov imm64, rax
record->thunk[0] = 0x48;
record->thunk[1] = 0xb8;
void* handler = &CrashForExceptionInNonABICompliantCodeRange;
memcpy(&record->thunk[2], &handler, 8);
// jmp rax
record->thunk[10] = 0xff;
record->thunk[11] = 0xe0;
// Protect reserved page against modifications.
DWORD old_protect;
CHECK(VirtualProtect(
start, sizeof(ExceptionHandlerRecord), PAGE_EXECUTE_READ, &old_protect));
CHECK(RtlAddFunctionTable(
&record->runtime_function, 1, reinterpret_cast<DWORD64>(start)));
}
void UnregisterNonABICompliantCodeRange(void* start) {
ExceptionHandlerRecord* record =
reinterpret_cast<ExceptionHandlerRecord*>(start);
CHECK(RtlDeleteFunctionTable(&record->runtime_function));
}
#endif // _WIN64
} // namespace
void SetupV8CodeRangeHook() {
gin::Debug::SetCodeRangeCreatedCallback(RegisterNonABICompliantCodeRange);
gin::Debug::SetCodeRangeDeletedCallback(UnregisterNonABICompliantCodeRange);
}
CrashReporterWin::CrashReporterWin() {
}
@ -63,14 +175,12 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
// to allow any previous handler to detach in the correct order.
breakpad_.reset();
int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION |
google_breakpad::ExceptionHandler::HANDLER_PURECALL;
breakpad_.reset(new google_breakpad::ExceptionHandler(
temp_dir.value(),
FilterCallback,
MinidumpCallback,
this,
handler_types,
google_breakpad::ExceptionHandler::HANDLER_ALL,
kSmallDumpType,
pipe_name.c_str(),
GetCustomInfo(product_name, version, company_name)));
@ -83,6 +193,14 @@ void CrashReporterWin::SetUploadParameters() {
upload_parameters_["platform"] = "win32";
}
int CrashReporterWin::CrashForException(EXCEPTION_POINTERS* info) {
if (breakpad_) {
breakpad_->WriteMinidumpForException(info);
TerminateProcessWithoutDump();
}
return EXCEPTION_CONTINUE_SEARCH;
}
// static
bool CrashReporterWin::FilterCallback(void* context,
EXCEPTION_POINTERS* exinfo,

Просмотреть файл

@ -17,6 +17,9 @@ template <typename T> struct DefaultSingletonTraits;
namespace crash_reporter {
// Hook up V8 to breakpad.
void SetupV8CodeRangeHook();
class CrashReporterWin : public CrashReporter {
public:
static CrashReporterWin* GetInstance();
@ -29,6 +32,9 @@ class CrashReporterWin : public CrashReporter {
bool skip_system_crash_handler) override;
void SetUploadParameters() override;
// Crashes the process after generating a dump for the provided exception.
int CrashForException(EXCEPTION_POINTERS* info);
private:
friend struct DefaultSingletonTraits<CrashReporterWin>;