From 454d5b48715772889db12d142486e75a3a4dfed3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 26 Feb 2025 15:58:18 +0200 Subject: #3591 Reprot SEH directly to bugsplat Rethrowing SEH via std::exception results ina callstack that ends at rethrow. --- indra/llcommon/llapp.h | 2 +- indra/llcommon/llcoros.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 3d18864b80..57f5a112d9 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -282,7 +282,7 @@ public: LLRunner& getRunner() { return mRunner; } #ifdef LL_WINDOWS - virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } + virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; } #endif public: diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 1539b48bd3..ab56a3d3b7 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -310,18 +310,20 @@ namespace static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop) { if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on return EXCEPTION_CONTINUE_SEARCH; } - else + else if (!LLApp::instance()->reportCrashToBugsplat((void*)exception_infop)) { // handle it return EXCEPTION_EXECUTE_HANDLER; } + + return EXCEPTION_CONTINUE_SEARCH; } void sehandle(const LLCoros::callable_t& callable) -- cgit v1.2.3 From 39610cbfb381eec0b144f22cd1b34a4ff6911322 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 26 Feb 2025 19:11:57 +0200 Subject: #3591 Remove now pointless rethrow --- indra/llcommon/llcoros.cpp | 36 +++++++++--------------------------- indra/llcommon/llcoros.h | 27 --------------------------- 2 files changed, 9 insertions(+), 54 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index ab56a3d3b7..b16f166d28 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -228,22 +228,6 @@ 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; @@ -312,14 +296,19 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop) { - if (code == STATUS_MSC_EXCEPTION) + if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop)) + { + // Handled + return EXCEPTION_CONTINUE_SEARCH; + } + else if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on return EXCEPTION_CONTINUE_SEARCH; } - else if (!LLApp::instance()->reportCrashToBugsplat((void*)exception_infop)) + else { - // handle it + // handle it, convert to std::exception return EXCEPTION_EXECUTE_HANDLER; } @@ -381,14 +370,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) // viewer will carry on. LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } - catch (...) - { - // 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()); - } + // uncaught exception by default will cause std::terminate() } //static diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index c3820ae987..913414fbc1 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -170,19 +170,6 @@ public: */ 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 * name for an explicitly-launched coroutine, or "mainN" for the default @@ -327,20 +314,6 @@ private: void toplevel(std::string name, callable_t callable); 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 mExceptionQueue; S32 mStackSize; -- cgit v1.2.3 From ed394cd5a07d69e9007ad50819a01911645cadcd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 3 Mar 2025 22:49:52 +0200 Subject: #3591 rethrow should be mac specific Jumped the gun a bit, since reportCrashToBugsplat is OS specific, restore rethrow for other systems. --- indra/llcommon/llcoros.cpp | 27 ++++++++++++++++++++++++++- indra/llcommon/llcoros.h | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index b16f166d28..ea2d102de9 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -228,6 +228,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; @@ -370,7 +386,16 @@ void LLCoros::toplevel(std::string name, callable_t callable) // viewer will carry on. LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } - // uncaught exception by default will cause std::terminate() +#ifndef LL_WINDOWS + catch (...) + { + // 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 // ! LL_WINDOWS } //static diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 913414fbc1..c3820ae987 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -170,6 +170,19 @@ public: */ 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 * name for an explicitly-launched coroutine, or "mainN" for the default @@ -314,6 +327,20 @@ private: void toplevel(std::string name, callable_t callable); 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 mExceptionQueue; S32 mStackSize; -- cgit v1.2.3 From 851039cf4ed0de89b3a79b1e12483879a120576c Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Sat, 27 Apr 2024 10:49:31 -0700 Subject: Add timestamp to snapshot file names This changeset adds a timestamp in the format of "YYYY-MM-DD_HHSS" to snapshot filenames. This is useful for understanding when a snapshot was taken, chronologically ordering files, and is less confusing than the current method of adding a number to the snapshot name, as it does not result in interleaving of old and new snapshots inside a directory. --- indra/llcommon/lldate.cpp | 9 +++++++++ indra/llcommon/lldate.h | 1 + 2 files changed, 10 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index b38864688d..5205699b92 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -77,6 +77,15 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } +std::string LLDate::toLocalDateString (std::string fmt) const +{ + LL_PROFILE_ZONE_SCOPED; + + time_t locSeconds = (time_t) mSecondsSinceEpoch; + struct tm * lt = localtime (&locSeconds); + return toHTTPDateString(lt, fmt); +} + std::string LLDate::toHTTPDateString (std::string fmt) const { LL_PROFILE_ZONE_SCOPED; diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 1a69a04232..34c8692f20 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -77,6 +77,7 @@ public: std::string asRFC1123() const; void toStream(std::ostream&) const; bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; + std::string toLocalDateString(std::string fmt) const; std::string toHTTPDateString (std::string fmt) const; static std::string toHTTPDateString (tm * gmt, std::string fmt); /** -- cgit v1.2.3 From 7e9e5bf872f7866619343c14208a7f1fba6f5094 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 12 Mar 2025 16:03:37 +0200 Subject: #3591 Restructure SE to not catch LLContinueError It was reporting shutdown as crashes to bugsplat --- indra/llcommon/llcoros.cpp | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index ea2d102de9..9e95d9c85f 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -331,12 +331,34 @@ U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop) return EXCEPTION_CONTINUE_SEARCH; } -void sehandle(const LLCoros::callable_t& callable) +void cpphandle(const LLCoros::callable_t& callable, const std::string& name) { - __try + // SE and C++ can not coexists, thus two handlers + try { callable(); } + catch (const LLCoros::Stop& exc) + { + LL_INFOS("LLCoros") << "coroutine " << name << " terminating because " + << exc.what() << LL_ENDL; + } + catch (const LLContinueError&) + { + // Any uncaught exception derived from LLContinueError will be caught + // here and logged. This coroutine will terminate but the rest of the + // viewer will carry on. + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); + } +} + +void sehandle(const LLCoros::callable_t& callable, const std::string& name) +{ + __try + { + // handle stop and continue exceptions first + cpphandle(callable, name); + } __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) { // convert to C++ styled exception @@ -347,16 +369,7 @@ void sehandle(const LLCoros::callable_t& callable) throw std::exception(integer_string); } } - -#else // ! LL_WINDOWS - -inline void sehandle(const LLCoros::callable_t& callable) -{ - callable(); -} - -#endif // ! LL_WINDOWS - +#endif // LL_WINDOWS } // anonymous namespace // Top-level wrapper around caller's coroutine callable. @@ -369,10 +382,14 @@ void LLCoros::toplevel(std::string name, callable_t callable) // set it as current mCurrent.reset(&corodata); +#ifdef LL_WINDOWS + // can not use __try directly, toplevel requires unwinding, thus use of a wrapper + sehandle(callable, name); +#else // LL_WINDOWS // run the code the caller actually wants in the coroutine try { - sehandle(callable); + callable(); } catch (const Stop& exc) { @@ -386,7 +403,6 @@ void LLCoros::toplevel(std::string name, callable_t callable) // viewer will carry on. LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } -#ifndef LL_WINDOWS catch (...) { // Stash any OTHER kind of uncaught exception in the rethrow() queue @@ -395,7 +411,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) << name << LL_ENDL; LLCoros::instance().saveException(name, std::current_exception()); } -#endif // ! LL_WINDOWS +#endif // else LL_WINDOWS } //static -- cgit v1.2.3 From d484fff77d73931e70c896b9a88db547c4922dbd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 25 Mar 2025 14:30:29 +0200 Subject: #3596 Don't supress exceptions in WorkQueue We need those to know about problems. --- indra/llcommon/workqueue.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index 6066e74fb5..dace95aaf2 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -17,6 +17,7 @@ // std headers // external library headers // other Linden headers +#include "llapp.h" #include "llcoros.h" #include LLCOROS_MUTEX_HEADER #include "llerror.h" @@ -102,19 +103,95 @@ std::string LL::WorkQueueBase::makeName(const std::string& name) return STRINGIZE("WorkQueue" << num); } +namespace +{ +#if LL_WINDOWS + + static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific + + U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop) + { + if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop)) + { + // Handled + return EXCEPTION_CONTINUE_SEARCH; + } + else if (code == STATUS_MSC_EXCEPTION) + { + // C++ exception, go on + return EXCEPTION_CONTINUE_SEARCH; + } + else + { + // handle it, convert to std::exception + return EXCEPTION_EXECUTE_HANDLER; + } + + return EXCEPTION_CONTINUE_SEARCH; + } + + void cpphandle(const LL::WorkQueueBase::Work& work) + { + // SE and C++ can not coexists, thus two handlers + try + { + work(); + } + catch (const LLContinueError&) + { + // Any uncaught exception derived from LLContinueError will be caught + // here and logged. This coroutine will terminate but the rest of the + // viewer will carry on. + LOG_UNHANDLED_EXCEPTION(STRINGIZE("LLContinue in work queue")); + } + } + + void sehandle(const LL::WorkQueueBase::Work& work) + { + __try + { + // handle stop and continue exceptions first + cpphandle(work); + } + __except (exception_filter(GetExceptionCode(), GetExceptionInformation())) + { + // convert to C++ styled exception + char integer_string[512]; + sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + throw std::exception(integer_string); + } + } +#endif // LL_WINDOWS +} // anonymous namespace + void LL::WorkQueueBase::callWork(const Work& work) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + +#ifdef LL_WINDOWS + // can not use __try directly, toplevel requires unwinding, thus use of a wrapper + sehandle(work); +#else // LL_WINDOWS try { work(); } - catch (...) + catch (LLContinueError&) { - // No matter what goes wrong with any individual work item, the worker - // thread must go on! Log our own instance name with the exception. LOG_UNHANDLED_EXCEPTION(getKey()); } + catch (...) + { + // Stash any other kind of uncaught exception to be rethrown by main thread. + LL_WARNS("LLCoros") << "Capturing uncaught exception in WorkQueueBase " + << getKey() << LL_ENDL; + + LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); + main_queue->post( + // Bind the current exception rethrow it in main loop. + [exc = std::current_exception()]() { std::rethrow_exception(exc); }); + } +#endif // else LL_WINDOWS } void LL::WorkQueueBase::error(const std::string& msg) -- cgit v1.2.3 From e671cb54fee9cb7b7da39953eb96eabc9151f687 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Sat, 29 Mar 2025 22:40:59 +0200 Subject: #3795 Crash at getVolatileAPRPool() --- indra/llcommon/workqueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index dace95aaf2..c8ece616b2 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -183,12 +183,12 @@ void LL::WorkQueueBase::callWork(const Work& work) catch (...) { // Stash any other kind of uncaught exception to be rethrown by main thread. - LL_WARNS("LLCoros") << "Capturing uncaught exception in WorkQueueBase " + LL_WARNS("LLCoros") << "Capturing and rethrowing uncaught exception in WorkQueueBase " << getKey() << LL_ENDL; LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); main_queue->post( - // Bind the current exception rethrow it in main loop. + // Bind the current exception, rethrow it in main loop. [exc = std::current_exception()]() { std::rethrow_exception(exc); }); } #endif // else LL_WINDOWS -- cgit v1.2.3