diff options
author | Howard Stearns <aech@lindenlab.com> | 2022-05-12 17:09:30 +0000 |
---|---|---|
committer | Howard Stearns <aech@lindenlab.com> | 2022-05-12 17:09:30 +0000 |
commit | 44f70be1e447664ec3ee050e85a8e14965fff4e7 (patch) | |
tree | c1a5c851a06dd77a27cbc135e4625701e743902e /indra/llcommon | |
parent | 4cfcbca748e825b4904e7f136fa625b1a0f79dfb (diff) | |
parent | 915de3eb556c22216fd3c76e2de4a2ab1953dbe0 (diff) |
Merged DRTVWR-544-maint into SL-12238
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llalignedarray.h | 10 | ||||
-rw-r--r-- | indra/llcommon/llcoros.cpp | 37 | ||||
-rw-r--r-- | indra/llcommon/llcoros.h | 35 |
3 files changed, 71 insertions, 11 deletions
diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index b68e9e0f82..da9d98c16c 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -116,14 +116,20 @@ void LLAlignedArray<T, alignment>::resize(U32 size) template <class T, U32 alignment> T& LLAlignedArray<T, alignment>::operator[](int idx) { - llassert(idx < mElementCount); + if(idx >= mElementCount || idx < 0) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } template <class T, U32 alignment> const T& LLAlignedArray<T, alignment>::operator[](int idx) const { - llassert(idx < mElementCount); + if (idx >= mElementCount || idx < 0) + { + LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; + } return mArray[idx]; } diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c2d353b0fc..14bfb98629 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -35,6 +35,7 @@ // STL headers // std headers #include <atomic> +#include <stdexcept> // external library headers #include <boost/bind.hpp> #include <boost/fiber/fiber.hpp> @@ -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; @@ -302,11 +319,11 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop, } } -void LLCoros::winlevel(const std::string& name, const callable_t& callable) +void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable) { __try { - toplevelTryWrapper(name, callable); + LLCoros::toplevelTryWrapper(name, callable); } __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name)) { @@ -321,7 +338,6 @@ void LLCoros::winlevel(const std::string& name, const callable_t& callable) throw std::exception(integer_string); } } - #endif void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) @@ -350,11 +366,19 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call } catch (...) { +#if LL_WINDOWS // Any OTHER kind of uncaught exception will cause the viewer to - // crash, hopefully informatively. + // 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 } } @@ -364,8 +388,9 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call 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); + // 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 diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index a94cfca19f..dbff921f16 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -38,6 +38,8 @@ #include "llinstancetracker.h" #include <boost/function.hpp> #include <string> +#include <exception> +#include <queue> // e.g. #include LLCOROS_MUTEX_HEADER #define LLCOROS_MUTEX_HEADER <boost/fiber/mutex.hpp> @@ -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 @@ -292,13 +307,27 @@ public: private: std::string generateDistinctName(const std::string& prefix) const; + void toplevelTryWrapper(const std::string& name, const callable_t& callable); #if LL_WINDOWS - void winlevel(const std::string& name, const callable_t& callable); + void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper #endif - void toplevelTryWrapper(const std::string& name, const callable_t& callable); - void toplevel(std::string name, callable_t callable); + 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); + + 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<ExceptionData> mExceptionQueue; S32 mStackSize; |