]> git.sesse.net Git - casparcg/blob - common/os/windows/win32_exception.cpp
75006bc25ad5e044edea19df8edd082aa0fcb393
[casparcg] / common / os / windows / win32_exception.cpp
1 #include "../../stdafx.h"
2
3 #include "win32_exception.h"
4
5 #include <boost/thread.hpp>
6 #include <boost/lexical_cast.hpp>
7
8 #include "../../thread_info.h"
9 #include "windows.h"
10
11 namespace caspar { namespace detail {
12
13 typedef struct tagTHREADNAME_INFO
14 {
15         DWORD dwType; // must be 0x1000
16         LPCSTR szName; // pointer to name (in user addr space)
17         DWORD dwThreadID; // thread ID (-1=caller thread)
18         DWORD dwFlags; // reserved for future use, must be zero
19 } THREADNAME_INFO;
20
21 inline void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
22 {
23         THREADNAME_INFO info;
24         {
25                 info.dwType = 0x1000;
26                 info.szName = szThreadName;
27                 info.dwThreadID = dwThreadID;
28                 info.dwFlags = 0;
29         }
30         __try
31         {
32                 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
33         }
34         __except (EXCEPTION_CONTINUE_EXECUTION){}       
35 }
36
37 } // namespace detail
38
39 bool& installed_for_thread()
40 {
41         static boost::thread_specific_ptr<bool> installed;
42
43         auto for_thread = installed.get();
44         
45         if (!for_thread)
46         {
47                 for_thread = new bool(false);
48                 installed.reset(for_thread);
49         }
50
51         return *for_thread;
52 }
53
54 void install_gpf_handler()
55 {
56 //#ifndef _DEBUG
57         _set_se_translator(win32_exception::Handler);
58         installed_for_thread() = true;
59 //#endif
60 }
61
62 void ensure_gpf_handler_installed_for_thread(
63                 const char* thread_description)
64 {
65         if (!installed_for_thread())
66         {
67                 install_gpf_handler();
68
69                 if (thread_description)
70                 {
71                         detail::SetThreadName(GetCurrentThreadId(), thread_description);
72                         get_thread_info().name = thread_description;
73                 }
74         }
75 }
76
77 msg_info_t generate_message(const EXCEPTION_RECORD& info)
78 {
79         switch (info.ExceptionCode)
80         {
81         case EXCEPTION_ACCESS_VIOLATION:
82                 {
83                         bool is_write = info.ExceptionInformation[0] == 1;
84                         auto bad_address = reinterpret_cast<const void*>(info.ExceptionInformation[1]);
85                         auto location = info.ExceptionAddress;
86
87                         return "Access violation at " + boost::lexical_cast<std::string>(location) + " trying to " + (is_write ? "write " : "read ") + boost::lexical_cast<std::string>(bad_address);
88                 }
89         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
90         case EXCEPTION_INT_DIVIDE_BY_ZERO:
91                 return "Divide by zero";
92         default:
93                 return "Win32 exception";
94         }
95 }
96
97 void win32_exception::Handler(unsigned int errorCode, EXCEPTION_POINTERS* pInfo) {
98         switch(errorCode)
99         {
100         case EXCEPTION_ACCESS_VIOLATION:
101                 CASPAR_THROW_EXCEPTION(win32_access_violation() << generate_message(*(pInfo->ExceptionRecord)));
102         default:
103                 CASPAR_THROW_EXCEPTION(win32_exception() << generate_message(*(pInfo->ExceptionRecord)));
104         }
105 }
106
107 }