log access violation on windows tinderboxen

where we currently have no good feedback when something
goes wrong.

Credit: Exception printing code written by
  msdn-whiteknight
as seen at
  https://stackoverflow.com/questions/22467604/how-can-you-use-capturestackbacktrace-to-capture-the-exception-stack-not-the-ca

Change-Id: I44c65b10c0b0151c3236521d62a824570d4cdccf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119561
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin 2021-07-27 15:15:21 +02:00 committed by Noel Grandin
parent 67faef71f9
commit 24b06b9c6b
2 changed files with 213 additions and 81 deletions

View file

@ -28,6 +28,12 @@ $(eval $(call gb_Executable_add_exception_objects,cppunittester,\
sal/cppunittester/cppunittester \
))
ifneq ($(strip $(debug)$(DEBUG)),)
$(eval $(call gb_Executable_use_system_win32_libs,cppunittester,\
dbghelp \
))
endif
ifeq ($(COM),MSC)
$(eval $(call gb_Executable_add_ldflags,cppunittester,\

View file

@ -23,6 +23,9 @@
#endif
#include <windows.h>
#endif
#if defined(_WIN32) && defined(_DEBUG)
#include "dbghelp.h"
#endif
#ifdef UNX
#include <sys/time.h>
@ -378,12 +381,11 @@ void reportResourceUsage([[maybe_unused]] const OUString& /*rPath*/)
}
SAL_IMPLEMENT_MAIN()
static bool main2()
{
bool ok = false;
OUString path;
try
{
#ifdef _WIN32
//Disable Dr-Watson in order to crash simply without popup dialogs under
//windows
@ -472,15 +474,139 @@ SAL_IMPLEMENT_MAIN()
ProtectedFixtureFunctor tests(testlib, args, protectors, result);
ok = tests.run();
reportResourceUsage(path);
return ok;
}
#if defined(_WIN32) && defined(_DEBUG)
//Prints stack trace based on exception context record
void printStack( CONTEXT* ctx )
{
constexpr int MaxNameLen = 256;
BOOL result;
HANDLE process;
HANDLE thread;
HMODULE hModule;
STACKFRAME64 stack;
ULONG frame;
DWORD64 displacement;
DWORD disp;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
char module[MaxNameLen];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
memset( &stack, 0, sizeof( STACKFRAME64 ) );
process = GetCurrentProcess();
thread = GetCurrentThread();
displacement = 0;
#if !defined(_M_AMD64)
stack.AddrPC.Offset = (*ctx).Eip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = (*ctx).Esp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = (*ctx).Ebp;
stack.AddrFrame.Mode = AddrModeFlat;
#endif
SymInitialize( process, NULL, TRUE ); //load symbols
std::unique_ptr<IMAGEHLP_LINE64> line(new IMAGEHLP_LINE64);
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
for( frame = 0; ; frame++ )
{
//get next call from stack
result = StackWalk64
(
#if defined(_M_AMD64)
IMAGE_FILE_MACHINE_AMD64,
#else
IMAGE_FILE_MACHINE_I386,
#endif
process,
thread,
&stack,
ctx,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL
);
if( !result )
break;
//get symbol name for address
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
SymFromAddr(process, ( ULONG64 )stack.AddrPC.Offset, &displacement, pSymbol);
//try to get line
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, line.get()))
{
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", pSymbol->Name, line->FileName, line->LineNumber, pSymbol->Address);
}
else
{
//failed to get line
printf("\tat %s, address 0x%0X.\n", pSymbol->Name, pSymbol->Address);
hModule = NULL;
lstrcpyA(module,"");
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(LPCTSTR)(stack.AddrPC.Offset), &hModule);
//at least print module name
if(hModule != NULL)GetModuleFileNameA(hModule,module,MaxNameLen);
printf ("in %s\n",module);
}
}
}
// The exception filter function:
LONG WINAPI ExpFilter(EXCEPTION_POINTERS* ex)
{
// we only want this active on the Jenkins tinderboxen
printf("*** Exception 0x%x occured ***\n\n",ex->ExceptionRecord->ExceptionCode);
printStack(ex->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER;
}
SAL_IMPLEMENT_MAIN()
{
bool ok = false;
// This magic kind of Windows-specific exception handling has to be in it's own function
// because it cannot be in a function that has objects with destructors.
__try
{
ok = main2();
}
__except (ExpFilter(GetExceptionInformation()))
{
}
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
#else
SAL_IMPLEMENT_MAIN()
{
bool ok = false;
try
{
ok = main2();
}
catch (const std::exception& e)
{
SAL_WARN("vcl.app", "Fatal exception: " << e.what());
}
reportResourceUsage(path);
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */