From bb4d02446fa215520a11f219ebca453d2dea0388 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 1 Dec 2020 18:21:43 +0200
Subject: [PATCH] SL-14347 Crash at ChoosePixelFormat SEH

---
 indra/llcommon/llcoros.cpp         | 22 +---------------------
 indra/llcommon/llexception.cpp     | 25 +++++++++++++++++++++++++
 indra/llcommon/llexception.h       | 10 ++++++++++
 indra/llwindow/llwindowwin32.cpp   | 23 ++++++++++++++++++++---
 indra/newview/llfeaturemanager.cpp | 18 +-----------------
 5 files changed, 57 insertions(+), 41 deletions(-)

diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 262929006dd..23419a52a75 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -56,10 +56,6 @@
 #include "stringize.h"
 #include "llexception.h"
 
-#if LL_WINDOWS
-#include <excpt.h>
-#endif
-
 // static
 LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller)
 {
@@ -253,29 +249,13 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl
 
 #if LL_WINDOWS
 
-static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
-
-U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
-{
-    if (code == STATUS_MSC_EXCEPTION)
-    {
-        // C++ exception, go on
-        return EXCEPTION_CONTINUE_SEARCH;
-    }
-    else
-    {
-        // handle it
-        return EXCEPTION_EXECUTE_HANDLER;
-    }
-}
-
 void LLCoros::winlevel(const callable_t& callable)
 {
     __try
     {
         callable();
     }
-    __except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
+    __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation()))
     {
         // convert to C++ styled exception
         // Note: it might be better to use _se_set_translator
diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp
index 5ce89586879..b584b0ff8b5 100644
--- a/indra/llcommon/llexception.cpp
+++ b/indra/llcommon/llexception.cpp
@@ -24,11 +24,14 @@
 // `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if
 // _Unwind_Backtrace is available without `_GNU_SOURCE`."
 #define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
+
 #if LL_WINDOWS
 // On Windows, header-only implementation causes macro collisions -- use
 // prebuilt library
 #define BOOST_STACKTRACE_LINK
+#include <excpt.h>
 #endif // LL_WINDOWS
+
 #include <boost/stacktrace.hpp>
 // other Linden headers
 #include "llerror.h"
@@ -85,3 +88,25 @@ void annotate_exception_(boost::exception& exc)
     // Anyway, which of us is really going to examine more than 100 frames?
     exc << errinfo_stacktrace(boost::stacktrace::stacktrace(1, 100));
 }
+
+#if LL_WINDOWS
+
+// For windows SEH exception handling we sometimes need a filter that will
+// separate C++ exceptions from C SEH exceptions
+static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
+
+U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
+{
+    if (code == STATUS_MSC_EXCEPTION)
+    {
+        // C++ exception, go on
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+    else
+    {
+        // handle it
+        return EXCEPTION_EXECUTE_HANDLER;
+    }
+}
+
+#endif //LL_WINDOWS
diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h
index 422dd8810a3..375bea4a573 100644
--- a/indra/llcommon/llexception.h
+++ b/indra/llcommon/llexception.h
@@ -102,4 +102,14 @@ 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&);
 
+
+#if LL_WINDOWS
+
+// 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 //LL_WINDOWS
+
 #endif /* ! defined(LL_LLEXCEPTION_H) */
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 28e835a5fa6..36148190fa9 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -38,6 +38,7 @@
 
 // Linden library includes
 #include "llerror.h"
+#include "llexception.h"
 #include "llfasttimer.h"
 #include "llgl.h"
 #include "llstring.h"
@@ -117,7 +118,7 @@ void show_window_creation_error(const std::string& title)
 	LL_WARNS("Window") << title << LL_ENDL;
 }
 
-HGLRC SafeCreateContext(HDC hdc)
+HGLRC SafeCreateContext(HDC &hdc)
 {
 	__try 
 	{
@@ -129,6 +130,22 @@ HGLRC SafeCreateContext(HDC hdc)
 	}
 }
 
+GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd)
+{
+    __try
+    {
+        return ChoosePixelFormat(hdc, ppfd);
+    }
+    __except (EXCEPTION_EXECUTE_HANDLER)
+    {
+        // convert to C++ styled exception
+        // C exception don't allow classes, so it's a regular char array
+        char integer_string[32];
+        sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
+        throw std::exception(integer_string);
+    }
+}
+
 //static
 BOOL LLWindowWin32::sIsClassRegistered = FALSE;
 
@@ -1234,7 +1251,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
     try
     {
         // Looks like ChoosePixelFormat can crash in case of faulty driver
-        if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
+        if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd)))
         {
             LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL;
             OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
@@ -1245,7 +1262,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO
     }
     catch (...)
     {
-        LL_WARNS("Window") << "ChoosePixelFormat failed." << LL_ENDL;
+        LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat");
         OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
             mCallbacks->translateString("MBError"), OSMB_OK);
         close();
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index d915a9fd269..dc9816c9f79 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -379,22 +379,6 @@ F32 gpu_benchmark();
 
 #if LL_WINDOWS
 
-static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
-
-U32 exception_benchmark_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
-{
-    if (code == STATUS_MSC_EXCEPTION)
-    {
-        // C++ exception, go on
-        return EXCEPTION_CONTINUE_SEARCH;
-    }
-    else
-    {
-        // handle it
-        return EXCEPTION_EXECUTE_HANDLER;
-    }
-}
-
 F32 logExceptionBenchmark()
 {
     // Todo: make a wrapper/class for SEH exceptions
@@ -403,7 +387,7 @@ F32 logExceptionBenchmark()
     {
         gbps = gpu_benchmark();
     }
-    __except (exception_benchmark_filter(GetExceptionCode(), GetExceptionInformation()))
+    __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation()))
     {
         // convert to C++ styled exception
         char integer_string[32];
-- 
GitLab