summaryrefslogtreecommitdiff
path: root/indra/llcommon/llexception.h
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-09-23 16:49:28 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-09-23 16:49:28 -0400
commit626920dda38a512b27c5e8fd79b0c9b09be01898 (patch)
tree89c54e31848048ee084005fd3a0a1316f5530966 /indra/llcommon/llexception.h
parentf6b3b5e803b0c08d55ecd10eac3e9e75518760a9 (diff)
parentd8e52ec001c476a2320f2d5caceb813465d707e4 (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.h117
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) */