diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llcommon/llcoros.cpp | 51 | ||||
| -rw-r--r-- | indra/llcommon/llexception.cpp | 50 | ||||
| -rw-r--r-- | indra/llcommon/llexception.h | 86 | ||||
| -rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 13 | ||||
| -rw-r--r-- | indra/newview/llappviewerwin32.cpp | 36 | ||||
| -rw-r--r-- | indra/newview/llfeaturemanager.cpp | 36 | ||||
| -rw-r--r-- | indra/test/test.cpp | 68 | 
7 files changed, 137 insertions, 203 deletions
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index a70e3d9ae7..f3943b7138 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -286,55 +286,6 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl      return name;  } -namespace -{ - -#if LL_WINDOWS - -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific - -U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) -{ -    if (code == STATUS_MSC_EXCEPTION) -    { -        // C++ exception, go on -        return EXCEPTION_CONTINUE_SEARCH; -    } -    else -    { -        // handle it -        return EXCEPTION_EXECUTE_HANDLER; -    } -} - -void sehandle(const LLCoros::callable_t& callable) -{ -    __try -    { -        callable(); -    } -    __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) -    { -        // convert to C++ styled exception -        // Note: it might be better to use _se_set_translator -        // if you want exception to inherit full callstack -        char integer_string[512]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } -} - -#else  // ! LL_WINDOWS - -inline void sehandle(const LLCoros::callable_t& callable) -{ -    callable(); -} - -#endif // ! LL_WINDOWS - -} // anonymous namespace -  // Top-level wrapper around caller's coroutine callable.  // Normally we like to pass strings and such by const reference -- but in this  // case, we WANT to copy both the name and the callable to our local stack! @@ -348,7 +299,7 @@ void LLCoros::toplevel(std::string name, callable_t callable)      // run the code the caller actually wants in the coroutine      try      { -        sehandle(callable); +        seh_catcher(callable);      }      catch (const Stop& exc)      { diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index c0154a569f..74b33f1e3b 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -15,7 +15,12 @@  #include "llexception.h"  // STL headers  // std headers +#include <iomanip> +#include <sstream>  #include <typeinfo> +#if LL_WINDOWS +#include <excpt.h> +#endif // LL_WINDOWS  // external library headers  #include <boost/exception/diagnostic_information.hpp>  #include <boost/exception/error_info.hpp> @@ -29,7 +34,6 @@  // On Windows, header-only implementation causes macro collisions -- use  // prebuilt library  #define BOOST_STACKTRACE_LINK -#include <excpt.h>  #endif // LL_WINDOWS  #include <boost/stacktrace.hpp> @@ -94,15 +98,34 @@ void annotate_exception_(boost::exception& exc)  // For windows SEH exception handling we sometimes need a filter that will  // separate C++ exceptions from C SEH exceptions -static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific +static constexpr U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific +static constexpr U32 STATUS_STACK_FULL    = 0xC00000FD; -U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +U32 ll_seh_filter( +    std::string& stacktrace, +    std::function<U32(U32, struct _EXCEPTION_POINTERS*)> filter, +    U32 code, +    struct _EXCEPTION_POINTERS* exception_infop)  { -    const auto stack = to_string(boost::stacktrace::stacktrace()); -    LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code -        << "\n Stack trace: \n" -        << stack << LL_ENDL; +    // By the time the handler gets control, the stack has been unwound, +    // so report the stack trace now at filter() time. +    // Even though stack overflow is a problem we would very much like to +    // diagnose, calling another function when the stack is already blown only +    // terminates us faster. +    if (code == STATUS_STACK_FULL) +    { +        stacktrace = "(stack overflow, no traceback)"; +    } +    else +    { +        stacktrace = boost::stacktrace::stacktrace().to_string(); +    } +     +    return filter(code, exception_infop); +} +U32 seh_filter(U32 code, struct _EXCEPTION_POINTERS*) +{      if (code == STATUS_MSC_EXCEPTION)      {          // C++ exception, go on @@ -110,9 +133,20 @@ U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)      }      else      { -        // handle it +        // This is a non-C++ exception, e.g. hardware check.          return EXCEPTION_EXECUTE_HANDLER;      }  } +void seh_rethrow(U32 code, const std::string& stacktrace) +{ +    std::ostringstream out; +    out << "Windows exception 0x" << std::hex << code; +    if (! stacktrace.empty()) +    { +        out << '\n' << stacktrace; +    } +    LLTHROW(Windows_SEH_exception(out.str())); +} +  #endif //LL_WINDOWS diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 68e609444e..3e50678b44 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -102,14 +102,94 @@ void crash_on_unhandled_exception_(const char*, int, const char*, const std::str       log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT)  void log_unhandled_exception_(const char*, int, const char*, const std::string&); +/***************************************************************************** +*   Structured Exception Handling +*****************************************************************************/ +// this is used in platform-generic code -- define outside #if LL_WINDOWS +struct Windows_SEH_exception: public std::runtime_error +{ +    Windows_SEH_exception(const std::string& what): std::runtime_error(what) {} +}; + +#if LL_WINDOWS //------------------------------------------------------------- + +#include <functional> + +// triadic variant specifies try(), filter(U32, struct _EXCEPTION_POINTERS*), +// handler(U32, const std::string& stacktrace) +// stacktrace may or may not be available +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto seh_catcher(TRYCODE&& trycode, FILTER&& filter, HANDLER&& handler) +{ +    // don't try to construct a std::function at the moment of Structured Exception +    std::function<U32(U32, struct _EXCEPTION_POINTERS*)> +        filter_function(std::forward<FILTER>(filter)); +    std::string stacktrace; +    __try +    { +        return std::forward<TRYCODE>(trycode)(); +    } +    __except (ll_seh_filter( +                  stacktrace, +                  filter_function, +                  GetExceptionCode(), +                  GetExceptionInformation())) +    { +        return std::forward<HANDLER>(handler)(GetExceptionCode(), stacktrace); +    } +} + +// dyadic variant specifies try(), handler(U32, stacktrace), assumes default filter +template <typename TRYCODE, typename HANDLER> +auto seh_catcher(TRYCODE&& trycode, HANDLER&& handler) +{ +    return seh_catcher( +        std::forward<TRYCODE>(trycode), +        seh_filter, +        std::forward<HANDLER>(handler)); +} -#if LL_WINDOWS +// monadic variant specifies try(), assumes default filter and handler +template <typename TRYCODE> +auto seh_catcher(TRYCODE&& trycode) +{ +    return seh_catcher( +        std::forward<TRYCODE>(trycode), +        seh_filter, +        seh_rethrow); +}  // SEH exception filtering for use in __try __except  // Separates C++ exceptions from C SEH exceptions  // Todo: might be good idea to do some kind of seh_to_msc_wrapper(function, ARGS&&); -U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop); +U32 ll_seh_filter( +    std::string& stacktrace, +    std::function<U32(U32, struct _EXCEPTION_POINTERS*)> filter, +    U32 code, +    struct _EXCEPTION_POINTERS* exception_infop); +U32 seh_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop); +void seh_rethrow(U32 code, const std::string& stacktrace); + +#else  // not LL_WINDOWS ----------------------------------------------------- + +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto seh_catcher(TRYCODE&& trycode, FILTER&&, HANDLER&&) +{ +    return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE, typename HANDLER> +auto seh_catcher(TRYCODE&& trycode, HANDLER&&) +{ +    return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE> +auto seh_catcher(TRYCODE&& trycode) +{ +    return std::forward<TRYCODE>(trycode)(); +} -#endif //LL_WINDOWS +#endif // not LL_WINDOWS -----------------------------------------------------  #endif /* ! defined(LL_LLEXCEPTION_H) */ diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d6b93b93d9..1535d00d50 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -163,18 +163,7 @@ HGLRC SafeCreateContext(HDC &hdc)  GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd)  { -    __try -    { -        return ChoosePixelFormat(hdc, ppfd); -    } -    __except (EXCEPTION_EXECUTE_HANDLER) -    { -        // convert to C++ styled exception -        // C exception don't allow classes, so it's a regular char array -        char integer_string[32]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } +    return seh_catcher(ChoosePixelFormat(hdc, ppfd));  }  //static diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 4c90a82fcb..a13e4de308 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -400,17 +400,10 @@ void ll_nvapi_init(NvDRSSessionHandle hSession)      }  } -//#define DEBUGGING_SEH_FILTER 1 -#if DEBUGGING_SEH_FILTER -#   define WINMAIN DebuggingWinMain -#else -#   define WINMAIN wWinMain -#endif - -int APIENTRY WINMAIN(HINSTANCE hInstance, -                     HINSTANCE hPrevInstance, -                     PWSTR     pCmdLine, -                     int       nCmdShow) +int APIENTRY wWinMain(HINSTANCE hInstance, +                      HINSTANCE hPrevInstance, +                      PWSTR     pCmdLine, +                      int       nCmdShow)  {      // Call Tracy first thing to have it allocate memory      // https://github.com/wolfpld/tracy/issues/196 @@ -559,27 +552,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,      return 0;  } -#if DEBUGGING_SEH_FILTER -// The compiler doesn't like it when you use __try/__except blocks -// in a method that uses object destructors. Go figure. -// This winmain just calls the real winmain inside __try. -// The __except calls our exception filter function. For debugging purposes. -int APIENTRY wWinMain(HINSTANCE hInstance, -                     HINSTANCE hPrevInstance, -                     PWSTR     lpCmdLine, -                     int       nCmdShow) -{ -    __try -    { -        WINMAIN(hInstance, hPrevInstance, lpCmdLine, nCmdShow); -    } -    __except( viewer_windows_exception_handler( GetExceptionInformation() ) ) -    { -        _tprintf( _T("Exception handled.\n") ); -    } -} -#endif -  void LLAppViewerWin32::disableWinErrorReporting()  {      std::string executable_name = gDirUtilp->getExecutableFilename(); diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 99139e6528..1f2ebd5092 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -40,6 +40,7 @@  #include "llappviewer.h"  #include "llbufferstream.h" +#include "llexception.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h"  #include "llworld.h" @@ -377,33 +378,6 @@ bool LLFeatureManager::parseFeatureTable(std::string filename)  F32 gpu_benchmark(); -#if LL_WINDOWS - -F32 logExceptionBenchmark() -{ -    // FIXME: gpu_benchmark uses many C++ classes on the stack to control state. -    //  SEH exceptions with our current exception handling options do not call -    //  destructors for these classes, resulting in an undefined state should -    //  this handler be invoked. -    F32 gbps = -1; -    __try -    { -        gbps = gpu_benchmark(); -    } -    __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) -    { -        // HACK - ensure that profiling is disabled -        LLGLSLShader::finishProfile(false); - -        // convert to C++ styled exception -        char integer_string[32]; -        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); -        throw std::exception(integer_string); -    } -    return gbps; -} -#endif -  bool LLFeatureManager::loadGPUClass()  {      if (!gSavedSettings.getBOOL("SkipBenchmark")) @@ -413,14 +387,12 @@ bool LLFeatureManager::loadGPUClass()          F32 gbps;          try          { -#if LL_WINDOWS -            gbps = logExceptionBenchmark(); -#else -            gbps = gpu_benchmark(); -#endif +            gbps = seh_catcher(gpu_benchmark);          }          catch (const std::exception& e)          { +            // HACK - ensure that profiling is disabled +            LLGLSLShader::finishProfile(false);              gbps = -1.f;              LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL;          } diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 1239b34d04..d1c65d6aa7 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -36,6 +36,7 @@  #include "linden_common.h"  #include "llerrorcontrol.h" +#include "llexception.h"  #include "lltut.h"  #include "chained_callback.h"  #include "stringize.h" @@ -68,13 +69,6 @@  #pragma warning (pop)  #endif -// On Mac, got: -// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define -// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if -// _Unwind_Backtrace is available without `_GNU_SOURCE`." -#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED -#include <boost/stacktrace.hpp> -  #include <fstream>  void wouldHaveCrashed(const std::string& message); @@ -524,64 +518,6 @@ void wouldHaveCrashed(const std::string& message)  static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; -// this is used in platform-generic code -- define outside #if LL_WINDOWS -struct Windows_SEH_exception: public std::runtime_error -{ -    Windows_SEH_exception(const std::string& what): std::runtime_error(what) {} -}; - -#if LL_WINDOWS - -static constexpr U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -static constexpr U32 STATUS_STACK_FULL    = 0xC00000FD; - -U32 seh_filter(U32 code, struct _EXCEPTION_POINTERS*) -{ -    if (code == STATUS_MSC_EXCEPTION) -    { -        // C++ exception, go on -- but TUT is supposed to have caught those already?! -        return EXCEPTION_CONTINUE_SEARCH; -    } -    else -    { -        // This is a non-C++ exception, e.g. hardware check. -        // By the time the handler gets control, the stack has been unwound, -        // so report the stack trace now at filter() time. -        // Sadly, even though, at the time of this writing, stack overflow is -        // the problem we would most like to diagnose, calling another -        // function when the stack is already blown only terminates us faster. -        if (code != STATUS_STACK_FULL) -        { -            std::cerr << boost::stacktrace::stacktrace() << std::endl; -        } -        // pass control into the handler block -        return EXCEPTION_EXECUTE_HANDLER; -    } -} - -template <typename CALLABLE0, typename CALLABLE1> -void seh_catcher(CALLABLE0&& trycode, CALLABLE1&& handler) -{ -    __try -    { -        trycode(); -    } -    __except (seh_filter(GetExceptionCode(), GetExceptionInformation())) -    { -        handler(GetExceptionCode()); -    } -} - -#else  // not LL_WINDOWS - -template <typename CALLABLE0, typename CALLABLE1> -void seh_catcher(CALLABLE0&& trycode, CALLABLE1&&) -{ -    trycode(); -} - -#endif // not LL_WINDOWS -  int main(int argc, char **argv)  {      // The following line must be executed to initialize Google Mock @@ -734,7 +670,7 @@ int main(int argc, char **argv)              }          },          // __except -        [mycallback](U32 code) +        [mycallback](U32 code, const std::string& /*stacktrace*/)          {              static std::map<U32, const char*> codes = {                  { 0xC0000005, "Access Violation" },  | 
