diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2024-09-23 16:49:28 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2024-09-23 16:49:28 -0400 |
commit | 626920dda38a512b27c5e8fd79b0c9b09be01898 (patch) | |
tree | 89c54e31848048ee084005fd3a0a1316f5530966 /indra/llcommon/llexception.h | |
parent | f6b3b5e803b0c08d55ecd10eac3e9e75518760a9 (diff) | |
parent | d8e52ec001c476a2320f2d5caceb813465d707e4 (diff) |
Merge remote branch 'develop' into release/luau-scripting for Maint B
Diffstat (limited to 'indra/llcommon/llexception.h')
-rw-r--r-- | indra/llcommon/llexception.h | 117 |
1 files changed, 111 insertions, 6 deletions
diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 15dacd76fc..ba225ad221 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -12,11 +12,15 @@ #if ! defined(LL_LLEXCEPTION_H) #define LL_LLEXCEPTION_H +#include "always_return.h" #include "stdtypes.h" #include <stdexcept> #include <boost/exception/exception.hpp> #include <boost/throw_exception.hpp> #include <boost/current_function.hpp> +#if LL_WINDOWS +#include <excpt.h> +#endif // LL_WINDOWS // "Found someone who can comfort me // But there are always exceptions..." @@ -103,14 +107,115 @@ 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 LLException +{ + Windows_SEH_exception(const std::string& what): LLException(what) {} +}; -#if LL_WINDOWS +namespace LL +{ +namespace seh +{ + +#if LL_WINDOWS //------------------------------------------------------------- + +void fill_stacktrace(std::string& stacktrace, U32 code); + +// wrapper around caller's U32 filter(U32 code, struct _EXCEPTION_POINTERS*) +// filter function: capture a stacktrace, if possible, before forwarding the +// call to the caller's filter() function +template <typename FILTER> +U32 filter_(std::string& stacktrace, FILTER&& filter, + U32 code, struct _EXCEPTION_POINTERS* exptrs) +{ + // By the time the handler gets control, the stack has been unwound, + // so report the stack trace now at filter() time. + fill_stacktrace(stacktrace, code); + return std::forward<FILTER>(filter)(code, exptrs); +} + +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto catcher_inner(std::string& stacktrace, + TRYCODE&& trycode, FILTER&& filter, HANDLER&& handler) +{ + __try + { + return std::forward<TRYCODE>(trycode)(); + } + __except (filter_(stacktrace, + std::forward<FILTER>(filter), + GetExceptionCode(), GetExceptionInformation())) + { + return always_return<decltype(trycode())>( + std::forward<HANDLER>(handler), GetExceptionCode(), stacktrace); + } +} + +// 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 catcher(TRYCODE&& trycode, FILTER&& filter, HANDLER&& handler) +{ + // Construct and destroy this stacktrace string in the outer function + // because we can't do either in the function with __try/__except. + std::string stacktrace; + return catcher_inner(stacktrace, + std::forward<TRYCODE>(trycode), + std::forward<FILTER>(filter), + std::forward<HANDLER>(handler)); +} + +// common_filter() handles the typical case in which we want our handler +// clause to handle only Structured Exceptions rather than explicitly-thrown +// C++ exceptions +U32 common_filter(U32 code, struct _EXCEPTION_POINTERS*); + +// dyadic variant specifies try(), handler(U32, stacktrace), assumes common_filter() +template <typename TRYCODE, typename HANDLER> +auto catcher(TRYCODE&& trycode, HANDLER&& handler) +{ + return catcher(std::forward<TRYCODE>(trycode), + common_filter, + std::forward<HANDLER>(handler)); +} + +[[noreturn]] void rethrow(U32 code, const std::string& stacktrace); + +// monadic variant specifies try(), assumes default filter and handler +template <typename TRYCODE> +auto catcher(TRYCODE&& trycode) +{ + return catcher(std::forward<TRYCODE>(trycode), rethrow); +} + +#else // not LL_WINDOWS ----------------------------------------------------- + +template <typename TRYCODE, typename FILTER, typename HANDLER> +auto catcher(TRYCODE&& trycode, FILTER&&, HANDLER&&) +{ + return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE, typename HANDLER> +auto catcher(TRYCODE&& trycode, HANDLER&&) +{ + return std::forward<TRYCODE>(trycode)(); +} + +template <typename TRYCODE> +auto catcher(TRYCODE&& trycode) +{ + return std::forward<TRYCODE>(trycode)(); +} -// 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); +#endif // not LL_WINDOWS ----------------------------------------------------- -#endif //LL_WINDOWS +} // namespace LL::seh +} // namespace LL #endif /* ! defined(LL_LLEXCEPTION_H) */ |