more reliable error logging

This commit is contained in:
Akash Mozumdar 2018-11-25 15:05:41 -05:00
parent c105f6700f
commit 49c4af8c2c
5 changed files with 71 additions and 41 deletions

View File

@ -4,9 +4,50 @@
#include "defs.h" #include "defs.h"
#include "util.h" #include "util.h"
#include "../vnrhook/texthook.h" #include "../vnrhook/texthook.h"
#include <sstream>
namespace namespace
{ {
char* GetCppExceptionInfo(EXCEPTION_POINTERS* exception)
{
// See https://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273
// Not very reliable so use __try
__try { return ((char****)exception->ExceptionRecord->ExceptionInformation[2])[3][1][1] + 8; }
__except (EXCEPTION_EXECUTE_HANDLER) { return "Could not find"; }
}
std::wstring lastError = L"Unknown error";
LONG WINAPI ExceptionLogger(EXCEPTION_POINTERS* exception)
{
MEMORY_BASIC_INFORMATION info = {};
VirtualQuery(exception->ExceptionRecord->ExceptionAddress, &info, sizeof(info));
wchar_t moduleName[MAX_PATH] = {};
GetModuleFileNameW((HMODULE)info.AllocationBase, moduleName, MAX_PATH);
std::wstringstream errorMsg;
errorMsg << std::uppercase << std::hex <<
L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl <<
L"Error address: " << (uint64_t)exception->ExceptionRecord->ExceptionAddress << std::endl <<
L"Error in module: " << moduleName << std::endl;
if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363)
errorMsg << L"Additional info: " << GetCppExceptionInfo(exception) << std::endl;
for (int i = 0; i < exception->ExceptionRecord->NumberParameters; ++i)
errorMsg << L"Additional info: " << exception->ExceptionRecord->ExceptionInformation[i] << std::endl;
lastError = errorMsg.str();
return EXCEPTION_CONTINUE_SEARCH;
}
void Terminate()
{
MessageBoxW(NULL, lastError.c_str(), L"Textractor ERROR", MB_ICONERROR);
std::abort();
}
class ProcessRecord class ProcessRecord
{ {
public: public:
@ -96,6 +137,7 @@ namespace
{ {
std::thread([] std::thread([]
{ {
Host::Setup();
SECURITY_DESCRIPTOR pipeSD = {}; SECURITY_DESCRIPTOR pipeSD = {};
InitializeSecurityDescriptor(&pipeSD, SECURITY_DESCRIPTOR_REVISION); InitializeSecurityDescriptor(&pipeSD, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&pipeSD, TRUE, NULL, FALSE); // Allow non-admin processes to connect to pipe created by admin host SetSecurityDescriptorDacl(&pipeSD, TRUE, NULL, FALSE); // Allow non-admin processes to connect to pipe created by admin host
@ -146,6 +188,7 @@ namespace
{ {
std::thread([] std::thread([]
{ {
Host::Setup();
for (std::wstring last; true; Sleep(50)) for (std::wstring last; true; Sleep(50))
if (auto text = Util::GetClipboardText()) if (auto text = Util::GetClipboardText())
if (last != text.value()) if (last != text.value())
@ -156,6 +199,17 @@ namespace
namespace Host namespace Host
{ {
void Setup()
{
static std::once_flag flag;
std::call_once(flag, []
{
AddVectoredExceptionHandler(FALSE, ExceptionLogger);
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)Terminate);
});
std::set_terminate(Terminate);
}
void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output) void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output)
{ {
OnAttach = onAttach; OnDetach = onDetach; OnCreate = onCreate; OnDestroy = onDestroy; TextThread::Output = output; OnAttach = onAttach; OnDetach = onDetach; OnCreate = onCreate; OnDestroy = onDestroy; TextThread::Output = output;

View File

@ -8,6 +8,7 @@ typedef std::function<void(std::shared_ptr<TextThread>)> ThreadEventCallback;
namespace Host namespace Host
{ {
void Setup();
void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output); void Start(ProcessEventCallback onAttach, ProcessEventCallback onDetach, ThreadEventCallback onCreate, ThreadEventCallback onDestroy, TextThread::OutputCallback output);
void Close(); void Close();

View File

@ -3,7 +3,14 @@
#include "host.h" #include "host.h"
#include "util.h" #include "util.h"
TextThread::TextThread(ThreadParam tp, HookParam hp, std::wstring name) : handle(threadCounter++), name(name), tp(tp), hp(hp) {} TextThread::TextThread(ThreadParam tp, HookParam hp, std::wstring name) :
handle(threadCounter++),
name(name),
tp(tp),
hp(hp),
deletionEvent(CreateEventW(nullptr, FALSE, FALSE, NULL)),
flushThread([&] { Host::Setup(); while (WaitForSingleObject(deletionEvent, 10) == WAIT_TIMEOUT) Flush(); })
{}
TextThread::~TextThread() TextThread::~TextThread()
{ {

View File

@ -37,8 +37,7 @@ private:
std::mutex bufferMutex; std::mutex bufferMutex;
std::wstring storage; std::wstring storage;
std::mutex storageMutex; std::mutex storageMutex;
HANDLE deletionEvent;
HANDLE deletionEvent = CreateEventW(nullptr, FALSE, FALSE, NULL); std::thread flushThread;
std::thread flushThread = std::thread([&] { while (WaitForSingleObject(deletionEvent, 10) == WAIT_TIMEOUT) Flush(); }); DWORD lastPushTime;
DWORD lastPushTime = GetTickCount();
}; };

View File

@ -1,45 +1,14 @@
#include "mainwindow.h" #include "mainwindow.h"
#include "host/host.h"
#include "misc.h"
#include <sstream> #include <sstream>
#include <QApplication> #include <QApplication>
namespace
{
char* GetCppExceptionInfo(EXCEPTION_POINTERS* exception)
{
// See https://blogs.msdn.microsoft.com/oldnewthing/20100730-00/?p=13273
// Not very reliable so use __try
__try { return ((char****)exception->ExceptionRecord->ExceptionInformation[2])[3][1][1] + 8; }
__except (EXCEPTION_EXECUTE_HANDLER) { return "Could not find"; }
}
LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS* exception)
{
MEMORY_BASIC_INFORMATION info = {};
VirtualQuery(exception->ExceptionRecord->ExceptionAddress, &info, sizeof(info));
wchar_t moduleName[MAX_PATH] = {};
GetModuleFileNameW((HMODULE)info.AllocationBase, moduleName, MAX_PATH);
std::wstringstream errorMsg;
errorMsg << std::uppercase << std::hex <<
L"Error code: " << exception->ExceptionRecord->ExceptionCode << std::endl <<
L"Error address: " << (uint64_t)exception->ExceptionRecord->ExceptionAddress << std::endl <<
L"Error in module: " << moduleName << std::endl;
if (exception->ExceptionRecord->ExceptionCode == 0xE06D7363)
errorMsg << L"Additional info: " << GetCppExceptionInfo(exception) << std::endl;
for (int i = 0; i < exception->ExceptionRecord->NumberParameters; ++i)
errorMsg << L"Additional info: " << exception->ExceptionRecord->ExceptionInformation[i] << std::endl;
MessageBoxW(NULL, errorMsg.str().c_str(), L"Textractor ERROR", MB_ICONERROR);
return EXCEPTION_CONTINUE_SEARCH;
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
SetUnhandledExceptionFilter(ExceptionHandler); Host::Setup();
QString exe = GetFullModuleName(GetCurrentProcessId());
SetCurrentDirectoryW(exe.left(exe.lastIndexOf("\\")).toStdWString().c_str());
QApplication a(argc, argv); QApplication a(argc, argv);
MainWindow w; MainWindow w;
w.show(); w.show();