diff options
-rw-r--r-- | indra/llcommon/llapp.h | 4 | ||||
-rw-r--r-- | indra/llcommon/llcoros.cpp | 74 | ||||
-rw-r--r-- | indra/llcommon/llcoros.h | 6 | ||||
-rw-r--r-- | indra/newview/llappviewerwin32.cpp | 10 | ||||
-rw-r--r-- | indra/newview/llappviewerwin32.h | 2 |
5 files changed, 69 insertions, 27 deletions
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index b9ae49aa44..c65fe21c9c 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -286,6 +286,10 @@ public: */ LLRunner& getRunner() { return mRunner; } +#ifdef LL_WINDOWS + virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } +#endif + public: typedef std::map<std::string, std::string> string_map; string_map mOptionMap; // Contains all command-line options and arguments in a map diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 51cf2138cb..ca2e7b38d7 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -277,15 +277,25 @@ 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) +U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name) { + // C++ exceptions were logged in toplevelTryWrapper, but not SEH + // log SEH exceptions here, to make sure it gets into bugsplat's + // report and because __try won't allow std::string operations + if (code != STATUS_MSC_EXCEPTION) + { + LL_WARNS() << "SEH crash in " << name << ", code: " << code << LL_ENDL; + } + // Handle bugsplat here, since GetExceptionInformation() can only be + // called from within filter for __except(filter), not from __except's {} + // Bugsplat should get all exceptions, C++ and SEH + LLApp::instance()->reportCrashToBugsplat(exception_infop); + + // Only convert non C++ exceptions. if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on @@ -298,38 +308,28 @@ U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) } } -void sehandle(const LLCoros::callable_t& callable) +void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable) { __try { - callable(); + LLCoros::toplevelTryWrapper(name, callable); } - __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) + __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) { - // convert to C++ styled exception + // convert to C++ styled exception for handlers other than bugsplat // Note: it might be better to use _se_set_translator // if you want exception to inherit full callstack + // + // in case of bugsplat this will get to exceptionTerminateHandler and + // looks like fiber will terminate application after that char integer_string[512]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + sprintf(integer_string, "SEH crash in %s, code: %lu\n", name.c_str(), GetExceptionCode()); throw std::exception(integer_string); } } +#endif -#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! -void LLCoros::toplevel(std::string name, callable_t callable) +void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) { // keep the CoroData on this top-level function's stack frame CoroData corodata(name); @@ -339,12 +339,12 @@ void LLCoros::toplevel(std::string name, callable_t callable) // run the code the caller actually wants in the coroutine try { - sehandle(callable); + callable(); } catch (const Stop& exc) { LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " - << exc.what() << LL_ENDL; + << exc.what() << LL_ENDL; } catch (const LLContinueError&) { @@ -355,14 +355,36 @@ void LLCoros::toplevel(std::string name, callable_t callable) } catch (...) { +#if LL_WINDOWS + // Any OTHER kind of uncaught exception will cause the viewer to + // crash, SEH handling should catch it and report to bugsplat. + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + // to not modify callstack + throw; +#else // Stash any OTHER kind of uncaught exception in the rethrow() queue // to be rethrown by the main fiber. LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine " << name << LL_ENDL; LLCoros::instance().saveException(name, std::current_exception()); +#endif } } +// 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! +void LLCoros::toplevel(std::string name, callable_t callable) +{ +#if LL_WINDOWS + // Because SEH can's have unwinding, need to call a wrapper + // 'try' is inside SEH handling to not catch LLContinue + sehHandle(name, callable); +#else + toplevelTryWrapper(name, callable); +#endif +} + //static void LLCoros::checkStop() { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 966ce03296..dbff921f16 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -307,7 +307,11 @@ public: private: std::string generateDistinctName(const std::string& prefix) const; - void toplevel(std::string name, callable_t callable); + void toplevelTryWrapper(const std::string& name, const callable_t& callable); +#if LL_WINDOWS + void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper +#endif + void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper struct CoroData; static CoroData& get_CoroData(const std::string& caller); void saveException(const std::string& name, std::exception_ptr exc); diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 6a504bbdbd..ee533875b6 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -708,6 +708,16 @@ bool LLAppViewerWin32::cleanup() return result; } +void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) +{ +#if defined(LL_BUGSPLAT) + if (sBugSplatSender) + { + sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo); + } +#endif // LL_BUGSPLAT +} + void LLAppViewerWin32::initLoggingAndGetLastDuration() { LLAppViewer::initLoggingAndGetLastDuration(); diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 3e3fc55151..82b6b0c77c 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -43,6 +43,8 @@ public: bool init() override; // Override to do application initialization bool cleanup() override; + void reportCrashToBugsplat(void* pExcepInfo) override; + protected: void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info. void initConsole() override; // Initialize OS level debugging console. |