1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
// **************************************************************************
// * 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_CONTINUE_EXECUTION) {}
}
/*
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); }
|