From efd41b35acaae88f49a2f9167bf76cbbede1a950 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 26 Jan 2022 02:26:19 +0200 Subject: OPEN-358 Readable error --- indra/llcommon/llalignedarray.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index b68e9e0f82..5f52bc0b15 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -116,14 +116,20 @@ void LLAlignedArray::resize(U32 size) template T& LLAlignedArray::operator[](int idx) { - llassert(idx < mElementCount); + if(idx >= mElementCount) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } template const T& LLAlignedArray::operator[](int idx) const { - llassert(idx < mElementCount); + if (idx >= mElementCount) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } -- cgit v1.2.3 From 855f53901a2265400797f33f3fb8b53ddc6cc07f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 5 Feb 2022 02:52:56 +0200 Subject: SL-16799 Clean up use of hardcoded folder names --- indra/llcommon/llalignedarray.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index 5f52bc0b15..da9d98c16c 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -116,7 +116,7 @@ void LLAlignedArray::resize(U32 size) template T& LLAlignedArray::operator[](int idx) { - if(idx >= mElementCount) + if(idx >= mElementCount || idx < 0) { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } @@ -126,7 +126,7 @@ T& LLAlignedArray::operator[](int idx) template const T& LLAlignedArray::operator[](int idx) const { - if (idx >= mElementCount) + if (idx >= mElementCount || idx < 0) { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } -- cgit v1.2.3 From 236593e997e931580d3bd3192b12e450c8054b07 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 11 Feb 2022 20:26:00 +0200 Subject: Revert "SL-14961 Coroutine crash was not reported to bugsplat" Will be replaced with retrow from nat --- indra/llcommon/llapp.h | 4 ---- indra/llcommon/llcoros.cpp | 56 +++++++++++++--------------------------------- indra/llcommon/llcoros.h | 7 +++--- 3 files changed, 19 insertions(+), 48 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index c65fe21c9c..b9ae49aa44 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -286,10 +286,6 @@ public: */ LLRunner& getRunner() { return mRunner; } -#ifdef LL_WINDOWS - virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } -#endif - public: typedef std::map 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 75fc0fec99..6a534951ff 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -264,21 +264,8 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, const std::string& name) +U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) { - // 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 @@ -291,29 +278,29 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, } } -void LLCoros::winlevel(const std::string& name, const callable_t& callable) +void LLCoros::winlevel(const callable_t& callable) { __try { - toplevelTryWrapper(name, callable); + callable(); } - __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) + __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) { - // convert to C++ styled exception for handlers other than bugsplat + // convert to C++ styled exception // 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 crash in %s, code: %lu\n", name.c_str(), GetExceptionCode()); + sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); throw std::exception(integer_string); } } #endif -void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) +// 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) { // keep the CoroData on this top-level function's stack frame CoroData corodata(name); @@ -323,12 +310,16 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call // run the code the caller actually wants in the coroutine try { +#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD + winlevel(callable); +#else callable(); +#endif } catch (const Stop& exc) { LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " - << exc.what() << LL_ENDL; + << exc.what() << LL_ENDL; } catch (const LLContinueError&) { @@ -341,25 +332,10 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call { // Any OTHER kind of uncaught exception will cause the viewer to // crash, hopefully informatively. - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); - // to not modify callstack - throw; + CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } } -// 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 - // Can not use __try in functions that require unwinding, so use one more wrapper - winlevel(name, callable); -#else - toplevelTryWrapper(name, callable); -#endif -} - //static void LLCoros::checkStop() { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index a94cfca19f..51f7380def 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -292,12 +292,11 @@ public: private: std::string generateDistinctName(const std::string& prefix) const; -#if LL_WINDOWS - void winlevel(const std::string& name, const callable_t& callable); -#endif - void toplevelTryWrapper(const std::string& name, const callable_t& callable); void toplevel(std::string name, callable_t callable); struct CoroData; +#if LL_WINDOWS + static void winlevel(const callable_t& callable); +#endif static CoroData& get_CoroData(const std::string& caller); S32 mStackSize; -- cgit v1.2.3 From 6c3507d6d358485c2a8e2fc4d915847cbeda3ee3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sun, 16 Dec 2018 14:31:32 -0500 Subject: SL-10190: Introduce LLCoros::saveException() and rethrow(). This mechanism uses a queue of std::exception_ptrs to transport an (otherwise) uncaught exception from a terminated coroutine to the thread's main fiber. The main loop calls LLCoros::rethrow() just after giving some cycles to ready coroutines that frame. # Conflicts: # indra/llcommon/llcoros.cpp # indra/llcommon/llcoros.h # indra/newview/llappviewer.cpp --- indra/llcommon/llcoros.cpp | 25 ++++++++++++++++++++++--- indra/llcommon/llcoros.h | 29 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 6a534951ff..a182d305e8 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -35,6 +35,7 @@ // STL headers // std headers #include +#include // external library headers #include #include @@ -214,6 +215,22 @@ std::string LLCoros::logname() return data.mName.empty()? data.getKey() : data.mName; } +void LLCoros::saveException(const std::string& name, std::exception_ptr exc) +{ + mExceptionQueue.emplace(name, exc); +} + +void LLCoros::rethrow() +{ + if (! mExceptionQueue.empty()) + { + ExceptionData front = mExceptionQueue.front(); + mExceptionQueue.pop(); + LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL; + std::rethrow_exception(front.exception); + } +} + void LLCoros::setStackSize(S32 stacksize) { LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; @@ -330,9 +347,11 @@ void LLCoros::toplevel(std::string name, callable_t callable) } catch (...) { - // Any OTHER kind of uncaught exception will cause the viewer to - // crash, hopefully informatively. - CRASH_ON_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + // 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()); } } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 51f7380def..59b2b91f96 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -38,6 +38,8 @@ #include "llinstancetracker.h" #include #include +#include +#include // e.g. #include LLCOROS_MUTEX_HEADER #define LLCOROS_MUTEX_HEADER @@ -156,6 +158,19 @@ public: * LLCoros::launch()). */ static std::string getName(); + + /** + * rethrow() is called by the thread's main fiber to propagate an + * exception from any coroutine into the main fiber, where it can engage + * the normal unhandled-exception machinery, up to and including crash + * reporting. + * + * LLCoros maintains a queue of otherwise-uncaught exceptions from + * terminated coroutines. Each call to rethrow() pops the first of those + * and rethrows it. When the queue is empty (normal case), rethrow() is a + * no-op. + */ + void rethrow(); /** * This variation returns a name suitable for log messages: the explicit @@ -298,6 +313,20 @@ private: static void winlevel(const callable_t& callable); #endif static CoroData& get_CoroData(const std::string& caller); + void saveException(const std::string& name, std::exception_ptr exc); + + struct ExceptionData + { + ExceptionData(const std::string& nm, std::exception_ptr exc): + name(nm), + exception(exc) + {} + // name of coroutine that originally threw this exception + std::string name; + // the thrown exception + std::exception_ptr exception; + }; + std::queue mExceptionQueue; S32 mStackSize; -- cgit v1.2.3 From 913bddf18fa33b54cdb6e30ebd290363e33e7f47 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sun, 16 Dec 2018 14:51:39 -0500 Subject: SL-10190: Slightly reduce conditional clutter in llcoros.{h,cpp}. Rename 'winlevel()' to 'sehandle()'; change it from a static member function to a free function, thus eliminating the conditional in llcoros.h. Elsewhere than Windows, provide a zero-cost pass-through sehandle() implementation, eliminating the conditional in toplevel(). # Conflicts: # indra/llcommon/llcoros.cpp # indra/llcommon/llcoros.h --- indra/llcommon/llcoros.cpp | 22 +++++++++++++++------- indra/llcommon/llcoros.h | 3 --- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index a182d305e8..51cf2138cb 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -277,6 +277,9 @@ 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 @@ -295,7 +298,7 @@ U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) } } -void LLCoros::winlevel(const callable_t& callable) +void sehandle(const LLCoros::callable_t& callable) { __try { @@ -312,7 +315,16 @@ void LLCoros::winlevel(const callable_t& callable) } } -#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 @@ -327,11 +339,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) // run the code the caller actually wants in the coroutine try { -#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD - winlevel(callable); -#else - callable(); -#endif + sehandle(callable); } catch (const Stop& exc) { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 59b2b91f96..966ce03296 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -309,9 +309,6 @@ private: std::string generateDistinctName(const std::string& prefix) const; void toplevel(std::string name, callable_t callable); struct CoroData; -#if LL_WINDOWS - static void winlevel(const callable_t& callable); -#endif static CoroData& get_CoroData(const std::string& caller); void saveException(const std::string& name, std::exception_ptr exc); -- cgit v1.2.3 From 935c1362a222f192bf913270d01f6c31c16e175b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 14 Feb 2022 22:26:43 +0200 Subject: Restored SL-14961 SL-14961 works better for windows than rethrow --- indra/llcommon/llapp.h | 4 +++ indra/llcommon/llcoros.cpp | 74 ++++++++++++++++++++++++++++++---------------- indra/llcommon/llcoros.h | 6 +++- 3 files changed, 57 insertions(+), 27 deletions(-) (limited to 'indra/llcommon') 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 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); -- cgit v1.2.3