sal/Executable_cppunittester.mk     |    6 
 sal/cppunittester/cppunittester.cxx |  284 +++++++++++++++++++++++++-----------
 2 files changed, 211 insertions(+), 79 deletions(-)

New commits:
commit 24b06b9c6bdb777dff385b0fbfc81d55d3d013a1
Author:     Noel Grandin <n...@peralex.com>
AuthorDate: Tue Jul 27 15:15:21 2021 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Wed Jul 28 18:34:08 2021 +0200

    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.gran...@collabora.co.uk>

diff --git a/sal/Executable_cppunittester.mk b/sal/Executable_cppunittester.mk
index 3b9016783b80..959b3cd8be47 100644
--- a/sal/Executable_cppunittester.mk
+++ b/sal/Executable_cppunittester.mk
@@ -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,\
diff --git a/sal/cppunittester/cppunittester.cxx 
b/sal/cppunittester/cppunittester.cxx
index 7ab54da02106..c899f320ad0c 100644
--- a/sal/cppunittester/cppunittester.cxx
+++ b/sal/cppunittester/cppunittester.cxx
@@ -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,109 +381,232 @@ 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
-        DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
-        SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
+    //Disable Dr-Watson in order to crash simply without popup dialogs under
+    //windows
+    DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
+    SetErrorMode(SEM_NOGPFAULTERRORBOX|dwMode);
 #ifdef _DEBUG // These functions are present only in the debugging runtime
-        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
-        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
-        _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
-        _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
-        _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
-        _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
+    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
+    _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE);
+    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
 #endif
 #endif
 
-        std::vector<CppUnit::Protector *> protectors;
-        CppUnit::TestResult result;
-        std::string args;
-        std::string testlib;
-        sal_uInt32 index = 0;
-        while (index < osl_getCommandArgCount())
+    std::vector<CppUnit::Protector *> protectors;
+    CppUnit::TestResult result;
+    std::string args;
+    std::string testlib;
+    sal_uInt32 index = 0;
+    while (index < osl_getCommandArgCount())
+    {
+        OUString arg = getArgument(index);
+        if (arg.startsWith("-env:CPPUNITTESTTARGET=", &path))
         {
-            OUString arg = getArgument(index);
-            if (arg.startsWith("-env:CPPUNITTESTTARGET=", &path))
-            {
-                ++index;
-                continue;
-            }
-            if (arg.startsWith("-env:"))
+            ++index;
+            continue;
+        }
+        if (arg.startsWith("-env:"))
+        {
+            ++index;
+            continue; // ignore it here - will be read later
+        }
+        if ( arg != "--protector" )
+        {
+            if (testlib.empty())
             {
-                ++index;
-                continue; // ignore it here - will be read later
+                testlib = OUStringToOString(arg, 
osl_getThreadTextEncoding()).getStr();
+                args += testlib;
             }
-            if ( arg != "--protector" )
+            else
             {
-                if (testlib.empty())
-                {
-                    testlib = OUStringToOString(arg, 
osl_getThreadTextEncoding()).getStr();
-                    args += testlib;
-                }
-                else
-                {
-                    args += ' ';
-                    args += OUStringToOString(arg, 
osl_getThreadTextEncoding()).getStr();
-                }
-                ++index;
-                continue;
-            }
-            if (osl_getCommandArgCount() - index < 3) {
-                usageFailure();
+                args += ' ';
+                args += OUStringToOString(arg, 
osl_getThreadTextEncoding()).getStr();
             }
-            OUString lib(getArgument(index + 1));
-            OUString sym(getArgument(index + 2));
+            ++index;
+            continue;
+        }
+        if (osl_getCommandArgCount() - index < 3) {
+            usageFailure();
+        }
+        OUString lib(getArgument(index + 1));
+        OUString sym(getArgument(index + 2));
 #ifndef DISABLE_DYNLOADING
-            osl::Module mod(lib, SAL_LOADMODULE_GLOBAL);
-            oslGenericFunction fn = mod.getFunctionSymbol(sym);
-            mod.release();
+        osl::Module mod(lib, SAL_LOADMODULE_GLOBAL);
+        oslGenericFunction fn = mod.getFunctionSymbol(sym);
+        mod.release();
 #else
-            oslGenericFunction fn = 0;
-            if (sym == "unoexceptionprotector")
-                fn = (oslGenericFunction) unoexceptionprotector;
-            else if (sym == "unobootstrapprotector")
-                fn = (oslGenericFunction) unobootstrapprotector;
-            else if (sym == "vclbootstrapprotector")
-                fn = (oslGenericFunction) vclbootstrapprotector;
-            else
-            {
-                std::cerr
-                    << "Only unoexceptionprotector or unobootstrapprotector 
protectors allowed"
-                    << std::endl;
-                std::exit(EXIT_FAILURE);
-            }
+        oslGenericFunction fn = 0;
+        if (sym == "unoexceptionprotector")
+            fn = (oslGenericFunction) unoexceptionprotector;
+        else if (sym == "unobootstrapprotector")
+            fn = (oslGenericFunction) unobootstrapprotector;
+        else if (sym == "vclbootstrapprotector")
+            fn = (oslGenericFunction) vclbootstrapprotector;
+        else
+        {
+            std::cerr
+                << "Only unoexceptionprotector or unobootstrapprotector 
protectors allowed"
+                << std::endl;
+            std::exit(EXIT_FAILURE);
+        }
 #endif
-            CppUnit::Protector *protector = fn == nullptr
-                ? nullptr
-                : (*reinterpret_cast< cppunittester::ProtectorFactory * 
>(fn))();
-            if (protector == nullptr) {
-                std::cerr
-                    << "Failure instantiating protector \"" << convertLazy(lib)
-                    << "\", \"" << convertLazy(sym) << '"' << std::endl;
-                std::exit(EXIT_FAILURE);
-            }
-            protectors.push_back(protector);
-            index+=3;
+        CppUnit::Protector *protector = fn == nullptr
+            ? nullptr
+            : (*reinterpret_cast< cppunittester::ProtectorFactory * >(fn))();
+        if (protector == nullptr) {
+            std::cerr
+                << "Failure instantiating protector \"" << convertLazy(lib)
+                << "\", \"" << convertLazy(sym) << '"' << std::endl;
+            std::exit(EXIT_FAILURE);
         }
+        protectors.push_back(protector);
+        index+=3;
+    }
+
+    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);
 
-        ProtectedFixtureFunctor tests(testlib, args, protectors, result);
-        ok = tests.run();
+    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);
+        }
     }
-    catch (const std::exception& e)
+}
+
+// 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()))
     {
-        SAL_WARN("vcl.app", "Fatal exception: " << e.what());
     }
+    return ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}
 
-    reportResourceUsage(path);
+#else
 
+SAL_IMPLEMENT_MAIN()
+{
+    bool ok = false;
+    try
+    {
+        ok = main2();
+    }
+    catch (const std::exception& e)
+    {
+        SAL_WARN("vcl.app", "Fatal exception: " << e.what());
+    }
     return ok ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
+#endif
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to