mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-28 08:26:14 +01:00
Merge branch 'resimplify-w32-veh' into 'main'
Re-simplify exception handling on Windows See merge request GNOME/glib!2031
This commit is contained in:
commit
601ef3b6be
@ -18,16 +18,16 @@
|
|||||||
|
|
||||||
/* Copy @cmdline into @debugger, and substitute @pid for `%p`
|
/* Copy @cmdline into @debugger, and substitute @pid for `%p`
|
||||||
* and @event for `%e`.
|
* and @event for `%e`.
|
||||||
* If @debugger_size (in bytes) is overflowed, return %FALSE.
|
* If @debugger_size (in wchar_ts) is overflowed, return %FALSE.
|
||||||
* Also returns %FALSE when `%` is followed by anything other
|
* Also returns %FALSE when `%` is followed by anything other
|
||||||
* than `e` or `p`.
|
* than `e` or `p`.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
_g_win32_subst_pid_and_event (char *debugger,
|
_g_win32_subst_pid_and_event_w (wchar_t *debugger,
|
||||||
gsize debugger_size,
|
gsize debugger_size,
|
||||||
const char *cmdline,
|
const wchar_t *cmdline,
|
||||||
DWORD pid,
|
DWORD pid,
|
||||||
guintptr event)
|
guintptr event)
|
||||||
{
|
{
|
||||||
gsize i = 0, dbg_i = 0;
|
gsize i = 0, dbg_i = 0;
|
||||||
/* These are integers, and they can't be longer than 20 characters
|
/* These are integers, and they can't be longer than 20 characters
|
||||||
@ -35,31 +35,31 @@ _g_win32_subst_pid_and_event (char *debugger,
|
|||||||
* Use 30 just to be sure.
|
* Use 30 just to be sure.
|
||||||
*/
|
*/
|
||||||
#define STR_BUFFER_SIZE 30
|
#define STR_BUFFER_SIZE 30
|
||||||
char pid_str[STR_BUFFER_SIZE] = {0};
|
wchar_t pid_str[STR_BUFFER_SIZE] = {0};
|
||||||
gsize pid_str_len;
|
gsize pid_str_len;
|
||||||
char event_str[STR_BUFFER_SIZE] = {0};
|
wchar_t event_str[STR_BUFFER_SIZE] = {0};
|
||||||
gsize event_str_len;
|
gsize event_str_len;
|
||||||
|
|
||||||
_snprintf_s (pid_str, STR_BUFFER_SIZE, G_N_ELEMENTS (pid_str), "%lu", pid);
|
_snwprintf_s (pid_str, STR_BUFFER_SIZE, G_N_ELEMENTS (pid_str), L"%lu", pid);
|
||||||
pid_str[G_N_ELEMENTS (pid_str) - 1] = 0;
|
pid_str[G_N_ELEMENTS (pid_str) - 1] = 0;
|
||||||
pid_str_len = strlen (pid_str);
|
pid_str_len = wcslen (pid_str);
|
||||||
_snprintf_s (event_str, STR_BUFFER_SIZE, G_N_ELEMENTS (pid_str), "%Iu", event);
|
_snwprintf_s (event_str, STR_BUFFER_SIZE, G_N_ELEMENTS (pid_str), L"%Iu", event);
|
||||||
event_str[G_N_ELEMENTS (pid_str) - 1] = 0;
|
event_str[G_N_ELEMENTS (pid_str) - 1] = 0;
|
||||||
event_str_len = strlen (event_str);
|
event_str_len = wcslen (event_str);
|
||||||
#undef STR_BUFFER_SIZE
|
#undef STR_BUFFER_SIZE
|
||||||
|
|
||||||
while (cmdline[i] != 0 && dbg_i < debugger_size)
|
while (cmdline[i] != 0 && dbg_i < debugger_size)
|
||||||
{
|
{
|
||||||
if (cmdline[i] != '%')
|
if (cmdline[i] != L'%')
|
||||||
debugger[dbg_i++] = cmdline[i++];
|
debugger[dbg_i++] = cmdline[i++];
|
||||||
else if (cmdline[i + 1] == 'p')
|
else if (cmdline[i + 1] == L'p')
|
||||||
{
|
{
|
||||||
gsize j = 0;
|
gsize j = 0;
|
||||||
while (j < pid_str_len && dbg_i < debugger_size)
|
while (j < pid_str_len && dbg_i < debugger_size)
|
||||||
debugger[dbg_i++] = pid_str[j++];
|
debugger[dbg_i++] = pid_str[j++];
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
else if (cmdline[i + 1] == 'e')
|
else if (cmdline[i + 1] == L'e')
|
||||||
{
|
{
|
||||||
gsize j = 0;
|
gsize j = 0;
|
||||||
while (j < event_str_len && dbg_i < debugger_size)
|
while (j < event_str_len && dbg_i < debugger_size)
|
||||||
|
275
glib/gwin32.c
275
glib/gwin32.c
@ -1035,10 +1035,32 @@ g_console_win32_init (void)
|
|||||||
* it will be non-NULL. Only used to later de-install the handler
|
* it will be non-NULL. Only used to later de-install the handler
|
||||||
* on library de-initialization.
|
* on library de-initialization.
|
||||||
*/
|
*/
|
||||||
static void *WinVEH_handle = NULL;
|
static void *WinVEH_handle = NULL;
|
||||||
|
|
||||||
|
#define DEBUGGER_BUFFER_SIZE (MAX_PATH + 1)
|
||||||
|
/* This is the debugger that we'll run on crash */
|
||||||
|
static wchar_t debugger[DEBUGGER_BUFFER_SIZE];
|
||||||
|
|
||||||
|
static gsize number_of_exceptions_to_catch = 0;
|
||||||
|
static DWORD *exceptions_to_catch = NULL;
|
||||||
|
|
||||||
|
static HANDLE debugger_wakeup_event = 0;
|
||||||
|
static DWORD debugger_spawn_flags = 0;
|
||||||
|
|
||||||
#include "gwin32-private.c"
|
#include "gwin32-private.c"
|
||||||
|
|
||||||
|
static char *
|
||||||
|
copy_chars (char *buffer,
|
||||||
|
gsize *buffer_size,
|
||||||
|
const char *to_copy)
|
||||||
|
{
|
||||||
|
gsize copy_count = MIN (strlen (to_copy), *buffer_size - 1);
|
||||||
|
memset (buffer, 0x20, copy_count);
|
||||||
|
strncpy_s (buffer, *buffer_size, to_copy, _TRUNCATE);
|
||||||
|
*buffer_size -= copy_count;
|
||||||
|
return &buffer[copy_count];
|
||||||
|
}
|
||||||
|
|
||||||
/* Handles exceptions (useful for debugging).
|
/* Handles exceptions (useful for debugging).
|
||||||
* Issues a DebugBreak() call if the process is being debugged (not really
|
* Issues a DebugBreak() call if the process is being debugged (not really
|
||||||
* useful - if the process is being debugged, this handler won't be invoked
|
* useful - if the process is being debugged, this handler won't be invoked
|
||||||
@ -1068,24 +1090,31 @@ static void *WinVEH_handle = NULL;
|
|||||||
* or for control flow.
|
* or for control flow.
|
||||||
*
|
*
|
||||||
* This function deliberately avoids calling any GLib code.
|
* This function deliberately avoids calling any GLib code.
|
||||||
|
* This is done on purpose. This function can be called when the program
|
||||||
|
* is in a bad state (crashing). It can also be called very early, as soon
|
||||||
|
* as the handler is installed. Therefore, it's imperative that
|
||||||
|
* it does as little as possible. Preferably, all the work that can be
|
||||||
|
* done in advance (when the program is not crashing yet) should be done
|
||||||
|
* in advance.
|
||||||
*/
|
*/
|
||||||
static LONG __stdcall
|
static LONG __stdcall
|
||||||
g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
||||||
{
|
{
|
||||||
EXCEPTION_RECORD *er;
|
EXCEPTION_RECORD *er;
|
||||||
char debugger[MAX_PATH + 1];
|
gsize i;
|
||||||
WCHAR *debugger_utf16;
|
|
||||||
const char *debugger_env = NULL;
|
|
||||||
const char *catch_list;
|
|
||||||
gboolean catch = FALSE;
|
|
||||||
STARTUPINFOW si;
|
STARTUPINFOW si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
HANDLE event;
|
#define ITOA_BUFFER_SIZE 100
|
||||||
SECURITY_ATTRIBUTES sa;
|
char itoa_buffer[ITOA_BUFFER_SIZE];
|
||||||
|
#define DEBUG_STRING_SIZE 1024
|
||||||
|
gsize dbgs = DEBUG_STRING_SIZE;
|
||||||
|
char debug_string[DEBUG_STRING_SIZE];
|
||||||
|
char *dbgp;
|
||||||
|
|
||||||
if (ExceptionInfo == NULL ||
|
if (ExceptionInfo == NULL ||
|
||||||
ExceptionInfo->ExceptionRecord == NULL ||
|
ExceptionInfo->ExceptionRecord == NULL ||
|
||||||
IsDebuggerPresent ())
|
IsDebuggerPresent () ||
|
||||||
|
debugger[0] == 0)
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
|
||||||
er = ExceptionInfo->ExceptionRecord;
|
er = ExceptionInfo->ExceptionRecord;
|
||||||
@ -1097,102 +1126,22 @@ g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
|||||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
catch_list = g_getenv ("G_VEH_CATCH");
|
for (i = 0; i < number_of_exceptions_to_catch; i++)
|
||||||
|
if (exceptions_to_catch[i] == er->ExceptionCode)
|
||||||
|
break;
|
||||||
|
|
||||||
while (!catch &&
|
if (i == number_of_exceptions_to_catch)
|
||||||
catch_list != NULL &&
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
catch_list[0] != 0)
|
|
||||||
{
|
|
||||||
unsigned long catch_code;
|
|
||||||
char *end;
|
|
||||||
errno = 0;
|
|
||||||
catch_code = strtoul (catch_list, &end, 16);
|
|
||||||
if (errno != NO_ERROR)
|
|
||||||
break;
|
|
||||||
catch_list = end;
|
|
||||||
if (catch_list != NULL && catch_list[0] == ',')
|
|
||||||
catch_list++;
|
|
||||||
if (catch_code == er->ExceptionCode)
|
|
||||||
catch = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (catch)
|
|
||||||
break;
|
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf_s (stderr,
|
|
||||||
"Exception code=0x%lx flags=0x%lx at 0x%p",
|
|
||||||
er->ExceptionCode,
|
|
||||||
er->ExceptionFlags,
|
|
||||||
er->ExceptionAddress);
|
|
||||||
|
|
||||||
switch (er->ExceptionCode)
|
|
||||||
{
|
|
||||||
case EXCEPTION_ACCESS_VIOLATION:
|
|
||||||
fprintf_s (stderr,
|
|
||||||
". Access violation - attempting to %s at address 0x%p\n",
|
|
||||||
er->ExceptionInformation[0] == 0 ? "read data" :
|
|
||||||
er->ExceptionInformation[0] == 1 ? "write data" :
|
|
||||||
er->ExceptionInformation[0] == 8 ? "execute data" :
|
|
||||||
"do something bad",
|
|
||||||
(void *) er->ExceptionInformation[1]);
|
|
||||||
break;
|
|
||||||
case EXCEPTION_IN_PAGE_ERROR:
|
|
||||||
fprintf_s (stderr,
|
|
||||||
". Page access violation - attempting to %s at address 0x%p with status %Ix\n",
|
|
||||||
er->ExceptionInformation[0] == 0 ? "read from an inaccessible page" :
|
|
||||||
er->ExceptionInformation[0] == 1 ? "write to an inaccessible page" :
|
|
||||||
er->ExceptionInformation[0] == 8 ? "execute data in page" :
|
|
||||||
"do something bad with a page",
|
|
||||||
(void *) er->ExceptionInformation[1],
|
|
||||||
er->ExceptionInformation[2]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf_s (stderr, "\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
fflush (stderr);
|
|
||||||
|
|
||||||
debugger_env = g_getenv ("G_DEBUGGER");
|
|
||||||
|
|
||||||
if (debugger_env == NULL)
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
|
|
||||||
/* Create an inheritable event */
|
|
||||||
memset (&si, 0, sizeof (si));
|
memset (&si, 0, sizeof (si));
|
||||||
memset (&pi, 0, sizeof (pi));
|
memset (&pi, 0, sizeof (pi));
|
||||||
memset (&sa, 0, sizeof (sa));
|
|
||||||
si.cb = sizeof (si);
|
si.cb = sizeof (si);
|
||||||
sa.nLength = sizeof (sa);
|
|
||||||
sa.bInheritHandle = TRUE;
|
|
||||||
event = CreateEvent (&sa, FALSE, FALSE, NULL);
|
|
||||||
|
|
||||||
/* Put process ID and event handle into debugger commandline */
|
|
||||||
if (!_g_win32_subst_pid_and_event (debugger, G_N_ELEMENTS (debugger),
|
|
||||||
debugger_env, GetCurrentProcessId (),
|
|
||||||
(guintptr) event))
|
|
||||||
{
|
|
||||||
CloseHandle (event);
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
debugger[MAX_PATH] = '\0';
|
|
||||||
|
|
||||||
debugger_utf16 = g_utf8_to_utf16 (debugger, -1, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
/* Run the debugger */
|
/* Run the debugger */
|
||||||
if (0 != CreateProcessW (NULL,
|
if (0 != CreateProcessW (NULL, debugger, NULL, NULL, TRUE, debugger_spawn_flags, NULL, NULL, &si, &pi))
|
||||||
debugger_utf16,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
TRUE,
|
|
||||||
g_getenv ("G_DEBUGGER_OLD_CONSOLE") != NULL ? 0 : CREATE_NEW_CONSOLE,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&si,
|
|
||||||
&pi))
|
|
||||||
{
|
{
|
||||||
CloseHandle (pi.hProcess);
|
CloseHandle (pi.hProcess);
|
||||||
CloseHandle (pi.hThread);
|
CloseHandle (pi.hThread);
|
||||||
@ -1202,13 +1151,67 @@ g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
|||||||
* up forever in case the debugger does not support
|
* up forever in case the debugger does not support
|
||||||
* event signalling.
|
* event signalling.
|
||||||
*/
|
*/
|
||||||
WaitForSingleObject (event, 60000);
|
WaitForSingleObject (debugger_wakeup_event, 60000);
|
||||||
|
|
||||||
|
dbgp = &debug_string[0];
|
||||||
|
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "Exception code=0x");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s (er->ExceptionCode, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, " flags=0x");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s (er->ExceptionFlags, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, " at 0x");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s ((guintptr) er->ExceptionAddress, itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
|
||||||
|
switch (er->ExceptionCode)
|
||||||
|
{
|
||||||
|
case EXCEPTION_ACCESS_VIOLATION:
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, ". Access violation - attempting to ");
|
||||||
|
if (er->ExceptionInformation[0] == 0)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "read data");
|
||||||
|
else if (er->ExceptionInformation[0] == 1)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "write data");
|
||||||
|
else if (er->ExceptionInformation[0] == 8)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "execute data");
|
||||||
|
else
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "do something bad");
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, " at address 0x");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s (er->ExceptionInformation[1], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
break;
|
||||||
|
case EXCEPTION_IN_PAGE_ERROR:
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, ". Page access violation - attempting to ");
|
||||||
|
if (er->ExceptionInformation[0] == 0)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "read from an inaccessible page");
|
||||||
|
else if (er->ExceptionInformation[0] == 1)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "write to an inaccessible page");
|
||||||
|
else if (er->ExceptionInformation[0] == 8)
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "execute data in page");
|
||||||
|
else
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "do something bad with a page");
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, " at address 0x");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s (er->ExceptionInformation[1], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, " with status ");
|
||||||
|
itoa_buffer[0] = 0;
|
||||||
|
_ui64toa_s (er->ExceptionInformation[2], itoa_buffer, ITOA_BUFFER_SIZE, 16);
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, itoa_buffer);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgp = copy_chars (dbgp, &dbgs, "\n");
|
||||||
|
OutputDebugStringA (debug_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_free (debugger_utf16);
|
|
||||||
|
|
||||||
CloseHandle (event);
|
|
||||||
|
|
||||||
/* Now the debugger is present, and we can try
|
/* Now the debugger is present, and we can try
|
||||||
* resuming execution, re-triggering the exception,
|
* resuming execution, re-triggering the exception,
|
||||||
* which will be caught by debugger this time around.
|
* which will be caught by debugger this time around.
|
||||||
@ -1219,20 +1222,88 @@ g_win32_veh_handler (PEXCEPTION_POINTERS ExceptionInfo)
|
|||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gsize
|
||||||
|
parse_catch_list (const wchar_t *catch_buffer,
|
||||||
|
DWORD *exceptions,
|
||||||
|
gsize num_exceptions)
|
||||||
|
{
|
||||||
|
const wchar_t *catch_list = catch_buffer;
|
||||||
|
gsize result = 0;
|
||||||
|
gsize i = 0;
|
||||||
|
|
||||||
|
while (catch_list != NULL &&
|
||||||
|
catch_list[0] != 0)
|
||||||
|
{
|
||||||
|
unsigned long catch_code;
|
||||||
|
wchar_t *end;
|
||||||
|
errno = 0;
|
||||||
|
catch_code = wcstoul (catch_list, &end, 16);
|
||||||
|
if (errno != NO_ERROR)
|
||||||
|
break;
|
||||||
|
catch_list = end;
|
||||||
|
if (catch_list != NULL && catch_list[0] == L',')
|
||||||
|
catch_list++;
|
||||||
|
if (exceptions && i < num_exceptions)
|
||||||
|
exceptions[i++] = catch_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_crash_handler_win32_init (void)
|
g_crash_handler_win32_init (void)
|
||||||
{
|
{
|
||||||
|
wchar_t debugger_env[DEBUGGER_BUFFER_SIZE];
|
||||||
|
#define CATCH_BUFFER_SIZE 1024
|
||||||
|
wchar_t catch_buffer[CATCH_BUFFER_SIZE];
|
||||||
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
|
||||||
if (WinVEH_handle != NULL)
|
if (WinVEH_handle != NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Do not register an exception handler if we're not supposed to catch any
|
/* Do not register an exception handler if we're not supposed to catch any
|
||||||
* exceptions. Exception handlers are considered dangerous to use, and can
|
* exceptions. Exception handlers are considered dangerous to use, and can
|
||||||
* break advanced exception handling such as in CLRs like C# or other managed
|
* break advanced exception handling such as in CLRs like C# or other managed
|
||||||
* code. See: https://blogs.msdn.microsoft.com/jmstall/2006/05/24/beware-of-the-vectored-exception-handler-and-managed-code/
|
* code. See: http://www.windows-tech.info/13/785f590867bd6316.php
|
||||||
*/
|
*/
|
||||||
if (g_getenv ("G_DEBUGGER") == NULL && g_getenv("G_VEH_CATCH") == NULL)
|
debugger_env[0] = 0;
|
||||||
|
if (!GetEnvironmentVariableW (L"G_DEBUGGER", debugger_env, DEBUGGER_BUFFER_SIZE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Create an inheritable event */
|
||||||
|
memset (&sa, 0, sizeof (sa));
|
||||||
|
sa.nLength = sizeof (sa);
|
||||||
|
sa.bInheritHandle = TRUE;
|
||||||
|
debugger_wakeup_event = CreateEvent (&sa, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
/* Put process ID and event handle into debugger commandline */
|
||||||
|
if (!_g_win32_subst_pid_and_event_w (debugger, G_N_ELEMENTS (debugger),
|
||||||
|
debugger_env, GetCurrentProcessId (),
|
||||||
|
(guintptr) debugger_wakeup_event))
|
||||||
|
{
|
||||||
|
CloseHandle (debugger_wakeup_event);
|
||||||
|
debugger_wakeup_event = 0;
|
||||||
|
debugger[0] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debugger[MAX_PATH] = L'\0';
|
||||||
|
|
||||||
|
catch_buffer[0] = 0;
|
||||||
|
if (GetEnvironmentVariableW (L"G_VEH_CATCH", catch_buffer, CATCH_BUFFER_SIZE))
|
||||||
|
{
|
||||||
|
number_of_exceptions_to_catch = parse_catch_list (catch_buffer, NULL, 0);
|
||||||
|
if (number_of_exceptions_to_catch > 0)
|
||||||
|
{
|
||||||
|
exceptions_to_catch = g_new0 (DWORD, number_of_exceptions_to_catch);
|
||||||
|
parse_catch_list (catch_buffer, exceptions_to_catch, number_of_exceptions_to_catch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetEnvironmentVariableW (L"G_DEBUGGER_OLD_CONSOLE", (wchar_t *) &debugger_spawn_flags, 1))
|
||||||
|
debugger_spawn_flags = 0;
|
||||||
|
else
|
||||||
|
debugger_spawn_flags = CREATE_NEW_CONSOLE;
|
||||||
|
|
||||||
WinVEH_handle = AddVectoredExceptionHandler (0, &g_win32_veh_handler);
|
WinVEH_handle = AddVectoredExceptionHandler (0, &g_win32_veh_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,34 +33,40 @@ static char *argv0 = NULL;
|
|||||||
static void
|
static void
|
||||||
test_subst_pid_and_event (void)
|
test_subst_pid_and_event (void)
|
||||||
{
|
{
|
||||||
const gchar not_enough[] = "too long when %e and %p are substituted";
|
const wchar_t not_enough[] = L"too long when %e and %p are substituted";
|
||||||
gchar debugger_3[3];
|
wchar_t debugger_3[3];
|
||||||
gchar debugger_not_enough[G_N_ELEMENTS (not_enough)];
|
wchar_t debugger_not_enough[G_N_ELEMENTS (not_enough)];
|
||||||
gchar debugger_enough[G_N_ELEMENTS (not_enough) + 1];
|
wchar_t debugger_enough[G_N_ELEMENTS (not_enough) + 1];
|
||||||
gchar debugger_big[65535] = {0};
|
char *debugger_enough_utf8;
|
||||||
|
wchar_t debugger_big[65535] = {0};
|
||||||
|
char *debugger_big_utf8;
|
||||||
gchar *output;
|
gchar *output;
|
||||||
guintptr be = (guintptr) 0xFFFFFFFF;
|
guintptr be = (guintptr) 0xFFFFFFFF;
|
||||||
DWORD bp = G_MAXSIZE;
|
DWORD bp = G_MAXSIZE;
|
||||||
|
|
||||||
/* %f is not valid */
|
/* %f is not valid */
|
||||||
g_assert_false (_g_win32_subst_pid_and_event (debugger_3, G_N_ELEMENTS (debugger_3),
|
g_assert_false (_g_win32_subst_pid_and_event_w (debugger_3, G_N_ELEMENTS (debugger_3),
|
||||||
"%f", 0, 0));
|
L"%f", 0, 0));
|
||||||
|
|
||||||
g_assert_false (_g_win32_subst_pid_and_event (debugger_3, G_N_ELEMENTS (debugger_3),
|
g_assert_false (_g_win32_subst_pid_and_event_w (debugger_3, G_N_ELEMENTS (debugger_3),
|
||||||
"string longer than 10", 0, 0));
|
L"string longer than 10", 0, 0));
|
||||||
/* 200 is longer than %e, so the string doesn't fit by 1 byte */
|
/* 200 is longer than %e, so the string doesn't fit by 1 byte */
|
||||||
g_assert_false (_g_win32_subst_pid_and_event (debugger_not_enough, G_N_ELEMENTS (debugger_not_enough),
|
g_assert_false (_g_win32_subst_pid_and_event_w (debugger_not_enough, G_N_ELEMENTS (debugger_not_enough),
|
||||||
"too long when %e and %p are substituted", 10, 200));
|
not_enough, 10, 200));
|
||||||
|
|
||||||
/* This should fit */
|
/* This should fit */
|
||||||
g_assert_true (_g_win32_subst_pid_and_event (debugger_enough, G_N_ELEMENTS (debugger_enough),
|
g_assert_true (_g_win32_subst_pid_and_event_w (debugger_enough, G_N_ELEMENTS (debugger_enough),
|
||||||
"too long when %e and %p are substituted", 10, 200));
|
not_enough, 10, 200));
|
||||||
g_assert_cmpstr (debugger_enough, ==, "too long when 200 and 10 are substituted");
|
debugger_enough_utf8 = g_utf16_to_utf8 (debugger_enough, -1, NULL, NULL, NULL);
|
||||||
|
g_assert_cmpstr (debugger_enough_utf8, ==, "too long when 200 and 10 are substituted");
|
||||||
|
g_free (debugger_enough_utf8);
|
||||||
|
|
||||||
g_assert_true (_g_win32_subst_pid_and_event (debugger_big, G_N_ELEMENTS (debugger_big),
|
g_assert_true (_g_win32_subst_pid_and_event_w (debugger_big, G_N_ELEMENTS (debugger_big),
|
||||||
"multipl%e big %e %entries and %pids are %provided here", bp, be));
|
L"multipl%e big %e %entries and %pids are %provided here", bp, be));
|
||||||
|
debugger_big_utf8 = g_utf16_to_utf8 (debugger_big, -1, NULL, NULL, NULL);
|
||||||
output = g_strdup_printf ("multipl%llu big %llu %lluntries and %luids are %lurovided here", (guint64) be, (guint64) be, (guint64) be, bp, bp);
|
output = g_strdup_printf ("multipl%llu big %llu %lluntries and %luids are %lurovided here", (guint64) be, (guint64) be, (guint64) be, bp, bp);
|
||||||
g_assert_cmpstr (debugger_big, ==, output);
|
g_assert_cmpstr (debugger_big_utf8, ==, output);
|
||||||
|
g_free (debugger_big_utf8);
|
||||||
g_free (output);
|
g_free (output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +101,6 @@ test_veh_crash_access_violation (void)
|
|||||||
/* Run a test that crashes */
|
/* Run a test that crashes */
|
||||||
g_test_trap_subprocess ("/win32/subprocess/access_violation", 0, 0);
|
g_test_trap_subprocess ("/win32/subprocess/access_violation", 0, 0);
|
||||||
g_test_trap_assert_failed ();
|
g_test_trap_assert_failed ();
|
||||||
g_test_trap_assert_stderr ("Exception code=0xc0000005*");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -105,20 +110,10 @@ test_veh_crash_illegal_instruction (void)
|
|||||||
/* Run a test that crashes */
|
/* Run a test that crashes */
|
||||||
g_test_trap_subprocess ("/win32/subprocess/illegal_instruction", 0, 0);
|
g_test_trap_subprocess ("/win32/subprocess/illegal_instruction", 0, 0);
|
||||||
g_test_trap_assert_failed ();
|
g_test_trap_assert_failed ();
|
||||||
g_test_trap_assert_stderr ("Exception code=0xc000001d*");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_veh_debug (void)
|
test_veh_debug (void)
|
||||||
{
|
|
||||||
/* Run a test that crashes and runs a debugger */
|
|
||||||
g_test_trap_subprocess ("/win32/subprocess/debuggee", 0, 0);
|
|
||||||
g_test_trap_assert_failed ();
|
|
||||||
g_test_trap_assert_stderr ("Exception code=0xc0000005*Debugger invoked, attaching to*");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
test_veh_debuggee (void)
|
|
||||||
{
|
{
|
||||||
/* Set up a debugger to be run on crash */
|
/* Set up a debugger to be run on crash */
|
||||||
gchar *command = g_strdup_printf ("%s %s", argv0, "%p %e");
|
gchar *command = g_strdup_printf ("%s %s", argv0, "%p %e");
|
||||||
@ -129,6 +124,15 @@ test_veh_debuggee (void)
|
|||||||
*/
|
*/
|
||||||
g_setenv ("G_DEBUGGER_OLD_CONSOLE", "1", TRUE);
|
g_setenv ("G_DEBUGGER_OLD_CONSOLE", "1", TRUE);
|
||||||
g_free (command);
|
g_free (command);
|
||||||
|
/* Run a test that crashes and runs a debugger */
|
||||||
|
g_test_trap_subprocess ("/win32/subprocess/debuggee", 0, 0);
|
||||||
|
g_test_trap_assert_failed ();
|
||||||
|
g_test_trap_assert_stderr ("Debugger invoked, attaching to*");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_veh_debuggee (void)
|
||||||
|
{
|
||||||
/* Crash */
|
/* Crash */
|
||||||
test_access_violation ();
|
test_access_violation ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user