mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 15:22:16 +00:00
Change read access violations to be non-fatal
This commit is contained in:
parent
deaced4bfa
commit
ea9b45d988
3 changed files with 107 additions and 17 deletions
|
@ -127,10 +127,10 @@ void DrawerCommandQueue::Finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](void *data)
|
[](void *data, const char *reason, bool fatal)
|
||||||
{
|
{
|
||||||
TryCatchData *d = (TryCatchData*)data;
|
TryCatchData *d = (TryCatchData*)data;
|
||||||
ReportFatalError(d->queue->active_commands[d->command_index], true);
|
ReportDrawerError(d->queue->active_commands[d->command_index], true, reason, fatal);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Wait for everyone to finish:
|
// Wait for everyone to finish:
|
||||||
|
@ -139,7 +139,14 @@ void DrawerCommandQueue::Finish()
|
||||||
queue->end_condition.wait(end_lock, [&]() { return queue->finished_threads == queue->threads.size(); });
|
queue->end_condition.wait(end_lock, [&]() { return queue->finished_threads == queue->threads.size(); });
|
||||||
|
|
||||||
if (!queue->thread_error.IsEmpty())
|
if (!queue->thread_error.IsEmpty())
|
||||||
I_FatalError("Fatal drawer error: %s", queue->thread_error.GetChars());
|
{
|
||||||
|
static bool first = true;
|
||||||
|
if (queue->thread_error_fatal)
|
||||||
|
I_FatalError("%s", queue->thread_error.GetChars());
|
||||||
|
else if (first)
|
||||||
|
Printf("%s\n", queue->thread_error.GetChars());
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up batch:
|
// Clean up batch:
|
||||||
|
|
||||||
|
@ -212,10 +219,10 @@ void DrawerCommandQueue::StartThreads()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[](void *data)
|
[](void *data, const char *reason, bool fatal)
|
||||||
{
|
{
|
||||||
TryCatchData *d = (TryCatchData*)data;
|
TryCatchData *d = (TryCatchData*)data;
|
||||||
ReportFatalError(d->queue->active_commands[d->command_index], true);
|
ReportDrawerError(d->queue->active_commands[d->command_index], true, reason, fatal);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Notify main thread that we finished:
|
// Notify main thread that we finished:
|
||||||
|
@ -241,23 +248,31 @@ void DrawerCommandQueue::StopThreads()
|
||||||
shutdown_flag = false;
|
shutdown_flag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawerCommandQueue::ReportFatalError(DrawerCommand *command, bool worker_thread)
|
void DrawerCommandQueue::ReportDrawerError(DrawerCommand *command, bool worker_thread, const char *reason, bool fatal)
|
||||||
{
|
{
|
||||||
if (worker_thread)
|
if (worker_thread)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> end_lock(Instance()->end_mutex);
|
std::unique_lock<std::mutex> end_lock(Instance()->end_mutex);
|
||||||
if (Instance()->thread_error.IsEmpty())
|
if (Instance()->thread_error.IsEmpty() || (!Instance()->thread_error_fatal && fatal))
|
||||||
Instance()->thread_error = command->DebugInfo();
|
{
|
||||||
|
Instance()->thread_error = reason + (FString)": " + command->DebugInfo();
|
||||||
|
Instance()->thread_error_fatal = fatal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
I_FatalError("Fatal drawer error: %s", command->DebugInfo().GetChars());
|
static bool first = true;
|
||||||
|
if (fatal)
|
||||||
|
I_FatalError("%s: %s", reason, command->DebugInfo().GetChars());
|
||||||
|
else if (first)
|
||||||
|
Printf("%s: %s\n", reason, command->DebugInfo().GetChars());
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
|
|
||||||
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data))
|
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data, const char *reason, bool fatal))
|
||||||
{
|
{
|
||||||
tryBlock(data);
|
tryBlock(data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ public:
|
||||||
virtual FString DebugInfo() = 0;
|
virtual FString DebugInfo() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data));
|
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data, const char *reason, bool fatal));
|
||||||
|
|
||||||
// Manages queueing up commands and executing them on worker threads
|
// Manages queueing up commands and executing them on worker threads
|
||||||
class DrawerCommandQueue
|
class DrawerCommandQueue
|
||||||
|
@ -132,6 +132,7 @@ class DrawerCommandQueue
|
||||||
std::condition_variable end_condition;
|
std::condition_variable end_condition;
|
||||||
size_t finished_threads = 0;
|
size_t finished_threads = 0;
|
||||||
FString thread_error;
|
FString thread_error;
|
||||||
|
bool thread_error_fatal = false;
|
||||||
|
|
||||||
int threaded_render = 0;
|
int threaded_render = 0;
|
||||||
DrawerThread single_core_thread;
|
DrawerThread single_core_thread;
|
||||||
|
@ -143,7 +144,7 @@ class DrawerCommandQueue
|
||||||
void Finish();
|
void Finish();
|
||||||
|
|
||||||
static DrawerCommandQueue *Instance();
|
static DrawerCommandQueue *Instance();
|
||||||
static void ReportFatalError(DrawerCommand *command, bool worker_thread);
|
static void ReportDrawerError(DrawerCommand *command, bool worker_thread, const char *reason, bool fatal);
|
||||||
|
|
||||||
DrawerCommandQueue();
|
DrawerCommandQueue();
|
||||||
~DrawerCommandQueue();
|
~DrawerCommandQueue();
|
||||||
|
@ -166,10 +167,10 @@ public:
|
||||||
T *c = (T*)data;
|
T *c = (T*)data;
|
||||||
c->Execute(&Instance()->single_core_thread);
|
c->Execute(&Instance()->single_core_thread);
|
||||||
},
|
},
|
||||||
[](void *data)
|
[](void *data, const char *reason, bool fatal)
|
||||||
{
|
{
|
||||||
T *c = (T*)data;
|
T *c = (T*)data;
|
||||||
ReportFatalError(c, false);
|
ReportDrawerError(c, false, reason, fatal);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -3407,23 +3407,97 @@ namespace
|
||||||
bool __declspec(thread) DrawerExceptionSetJumpResult;
|
bool __declspec(thread) DrawerExceptionSetJumpResult;
|
||||||
CONTEXT __declspec(thread) DrawerExceptionSetJumpContext;
|
CONTEXT __declspec(thread) DrawerExceptionSetJumpContext;
|
||||||
PVOID __declspec(thread) DrawerExceptionHandlerHandle;
|
PVOID __declspec(thread) DrawerExceptionHandlerHandle;
|
||||||
|
char __declspec(thread) *DrawerExceptionReason;
|
||||||
|
bool __declspec(thread) DrawerExceptionFatal;
|
||||||
|
|
||||||
LONG WINAPI DrawerExceptionHandler(_EXCEPTION_POINTERS *exceptionInfo)
|
LONG WINAPI DrawerExceptionHandler(_EXCEPTION_POINTERS *exceptionInfo)
|
||||||
{
|
{
|
||||||
//RtlRestoreContext(&DrawerExceptionSetJumpContext, exceptionInfo->ExceptionRecord);
|
|
||||||
*exceptionInfo->ContextRecord = DrawerExceptionSetJumpContext;
|
*exceptionInfo->ContextRecord = DrawerExceptionSetJumpContext;
|
||||||
|
|
||||||
|
DrawerExceptionFatal = false;
|
||||||
|
switch (exceptionInfo->ExceptionRecord->ExceptionCode)
|
||||||
|
{
|
||||||
|
default: DrawerExceptionReason = "Unknown exception code"; break;
|
||||||
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: DrawerExceptionReason = "Array bounds exceeded"; break;
|
||||||
|
case EXCEPTION_BREAKPOINT: DrawerExceptionReason = "Breakpoint"; break;
|
||||||
|
case EXCEPTION_DATATYPE_MISALIGNMENT: DrawerExceptionReason = "Datatype misalignment"; break;
|
||||||
|
case EXCEPTION_FLT_DENORMAL_OPERAND: DrawerExceptionReason = "Float denormal operand"; break;
|
||||||
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO: DrawerExceptionReason = "Float divide by zero"; break;
|
||||||
|
case EXCEPTION_FLT_INEXACT_RESULT: DrawerExceptionReason = "Float inexact result"; break;
|
||||||
|
case EXCEPTION_FLT_INVALID_OPERATION: DrawerExceptionReason = "Float invalid operation"; break;
|
||||||
|
case EXCEPTION_FLT_OVERFLOW: DrawerExceptionReason = "Float overflow"; break;
|
||||||
|
case EXCEPTION_FLT_STACK_CHECK: DrawerExceptionReason = "Float stack check"; break;
|
||||||
|
case EXCEPTION_FLT_UNDERFLOW: DrawerExceptionReason = "Float underflow"; break;
|
||||||
|
case EXCEPTION_INT_DIVIDE_BY_ZERO: DrawerExceptionReason = "Int divide by zero"; break;
|
||||||
|
case EXCEPTION_INT_OVERFLOW: DrawerExceptionReason = "Int overflow"; break;
|
||||||
|
case EXCEPTION_INVALID_DISPOSITION: DrawerExceptionReason = "Invalid disposition"; break;
|
||||||
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION: DrawerExceptionReason = "Noncontinuable exception"; break;
|
||||||
|
case EXCEPTION_PRIV_INSTRUCTION: DrawerExceptionReason = "Priv instruction"; break;
|
||||||
|
case EXCEPTION_SINGLE_STEP: DrawerExceptionReason = "Single step"; break;
|
||||||
|
case EXCEPTION_STACK_OVERFLOW: DrawerExceptionReason = "Stack overflow"; break;
|
||||||
|
|
||||||
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||||
|
DrawerExceptionReason = "Illegal instruction";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
|
if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 0)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "Read access violation";
|
||||||
|
}
|
||||||
|
else if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 1)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "Write access violation";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
else if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 8)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "User-mode data execution prevention (DEP) violation";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "Unknown access violation";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EXCEPTION_IN_PAGE_ERROR:
|
||||||
|
if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 0)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "In page read error";
|
||||||
|
}
|
||||||
|
else if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 1)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "In page write error";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
else if (exceptionInfo->ExceptionRecord->ExceptionInformation[0] == 8)
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "In page user-mode data execution prevention (DEP) error";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DrawerExceptionReason = "Unknown in page read error";
|
||||||
|
DrawerExceptionFatal = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_EXECUTION;
|
return EXCEPTION_CONTINUE_EXECUTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data))
|
void VectoredTryCatch(void *data, void(*tryBlock)(void *data), void(*catchBlock)(void *data, const char *reason, bool fatal))
|
||||||
{
|
{
|
||||||
DrawerExceptionSetJumpResult = false;
|
DrawerExceptionSetJumpResult = false;
|
||||||
RtlCaptureContext(&DrawerExceptionSetJumpContext);
|
RtlCaptureContext(&DrawerExceptionSetJumpContext);
|
||||||
if (DrawerExceptionSetJumpResult)
|
if (DrawerExceptionSetJumpResult)
|
||||||
{
|
{
|
||||||
RemoveVectoredExceptionHandler(DrawerExceptionHandlerHandle);
|
RemoveVectoredExceptionHandler(DrawerExceptionHandlerHandle);
|
||||||
catchBlock(data);
|
catchBlock(data, DrawerExceptionReason, DrawerExceptionFatal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue