// ************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #include "debug_minidump.h" #include <string> #include <sstream> #include <cassert> #include <cstdlib> //malloc(), free() #include "win.h" //includes "windows.h" #include "DbgHelp.h" //available for MSC only #pragma comment(lib, "Dbghelp.lib") namespace { LONG WINAPI writeDumpOnException(EXCEPTION_POINTERS* pExceptionInfo) { HANDLE hFile = ::CreateFile(L"exception.dmp", GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION exInfo = {}; exInfo.ThreadId = ::GetCurrentThreadId(); exInfo.ExceptionPointers = pExceptionInfo; exInfo.ClientPointers = FALSE; MINIDUMP_EXCEPTION_INFORMATION* exceptParam = pExceptionInfo ? &exInfo : nullptr; /*bool rv = */ ::MiniDumpWriteDump(::GetCurrentProcess (), //__in HANDLE hProcess, ::GetCurrentProcessId(), //__in DWORD ProcessId, hFile, //__in HANDLE hFile, MiniDumpWithDataSegs, //__in MINIDUMP_TYPE DumpType, ->Standard: MiniDumpNormal, Medium: MiniDumpWithDataSegs, Full: MiniDumpWithFullMemory exceptParam, //__in PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, nullptr, //__in PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, nullptr); //__in PMINIDUMP_CALLBACK_INFORMATION CallbackParam ::CloseHandle(hFile); } assert(false); return EXCEPTION_EXECUTE_HANDLER; } //ensure that a dump-file is written for uncaught exceptions struct OnStartup { OnStartup() { ::SetUnhandledExceptionFilter(writeDumpOnException); }} dummy; } void debug_tools::writeMinidump() { //force exception to catch the state of this thread and hopefully get a valid call stack __try { ::RaiseException(EXCEPTION_BREAKPOINT, 0, 0, nullptr); } __except (writeDumpOnException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) {} //don't use EXCEPTION_CONTINUE_EXECUTION: although used in most minidump examples this resulted in an infinite loop in tests //although it really should not: http://msdn.microsoft.com/en-us/library/c34eyfac.aspx } /* No need to include the "operator new" declarations into every compilation unit: [basic.stc.dynamic] "A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. Any such function definition replaces the default version provided in the library (17.6.4.6). The following allocation and deallocation functions (18.6) are implicitly declared in global scope in each translation unit of a program. void* operator new(std::size_t); void* operator new[](std::size_t); void operator delete(void*); void operator delete[](void*);" */ namespace { class BadAllocDetailed : public std::bad_alloc { public: explicit BadAllocDetailed(size_t allocSize) { errorMsg = "Memory allocation failed: "; errorMsg += numberToString(allocSize); } virtual const char* what() const throw() { return errorMsg.c_str(); } private: template <class T> static std::string numberToString(const T& number) //convert number to string the (slow) C++ way { std::ostringstream ss; ss << number; return ss.str(); } std::string errorMsg; }; } void* operator new(size_t size) { if (void* ptr = ::malloc(size)) return ptr; debug_tools::writeMinidump(); throw ::BadAllocDetailed(size); } void operator delete(void* ptr) { ::free(ptr); } void* operator new[](size_t size) { return operator new(size); } void operator delete[](void* ptr) { operator delete(ptr); }