From e409c0492f1b1ce63606c0b693c92cdb36dcc28b Mon Sep 17 00:00:00 2001
From: Oz Linden <oz@lindenlab.com>
Date: Sat, 2 Mar 2019 11:58:11 -0500
Subject: [PATCH] convert to an explicit USE_BUGSPLAT switch in cmake, revise
 LL_ERRS approach

---
 build.sh                           |  5 ---
 indra/CMakeLists.txt               | 10 +++++
 indra/cmake/Copy3rdPartyLibs.cmake |  4 +-
 indra/cmake/LLAddBuildTest.cmake   | 13 ++++++-
 indra/cmake/Variables.cmake        |  1 -
 indra/cmake/bugsplat.cmake         | 53 +++++++++++++++------------
 indra/llcommon/CMakeLists.txt      |  9 +++--
 indra/llcommon/llerror.cpp         | 21 +++++++----
 indra/llcommon/llerror.h           | 20 ++++++----
 indra/llcommon/llerrorcontrol.h    | 14 +++++--
 indra/llcommon/llleap.cpp          | 30 +--------------
 indra/llcommon/tests/wrapllerrs.h  |  5 ++-
 indra/llcorehttp/CMakeLists.txt    |  1 +
 indra/llimage/CMakeLists.txt       |  1 +
 indra/llmath/CMakeLists.txt        |  1 +
 indra/newview/CMakeLists.txt       | 36 +++++++++---------
 indra/newview/llappviewer.cpp      | 59 ++++++++++++++++++++++++++----
 indra/newview/llwatchdog.cpp       |  8 ++--
 indra/test/CMakeLists.txt          |  6 ++-
 indra/test/test.cpp                | 10 ++---
 20 files changed, 185 insertions(+), 122 deletions(-)

diff --git a/build.sh b/build.sh
index 9f070f2d107..aa6ba475a3b 100755
--- a/build.sh
+++ b/build.sh
@@ -129,11 +129,6 @@ pre_build()
     then # show that we're doing this, just not the contents
          echo source "$bugsplat_sh"
          source "$bugsplat_sh"
-         # important: we test this and use its value in [grand-]child processes
-         if [ -n "${BUGSPLAT_DB:-}" ]
-         then echo export BUGSPLAT_DB
-              export BUGSPLAT_DB
-         fi
     fi
     set -x
 
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt
index 62a8f3f003e..cf6029c4aeb 100644
--- a/indra/CMakeLists.txt
+++ b/indra/CMakeLists.txt
@@ -13,6 +13,7 @@ project(${ROOT_PROJECT_NAME})
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
 
 include(Variables)
+include(bugsplat)
 include(BuildVersion)
 
 if (NOT CMAKE_BUILD_TYPE)
@@ -89,6 +90,15 @@ set_property(
     PROPERTY VS_STARTUP_PROJECT secondlife-bin
     )
 
+if (USE_BUGSPLAT)
+    if (BUGSPLAT_DB)
+        message(STATUS "Building with BugSplat; database '${BUGSPLAT_DB}'")
+    else (BUGSPLAT_DB)
+        message(WARNING "Building with BugSplat, but no database name set (BUGSPLAT_DB)")
+    endif (BUGSPLAT_DB)
+else (USE_BUGSPLAT)
+    message(STATUS "Not building with BugSplat")
+endif (USE_BUGSPLAT)
 if (LL_TESTS)
   # Define after the custom targets are created so
   # individual apps can add themselves as dependencies
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index c73a1fdb47b..ebb6379aed4 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -50,7 +50,7 @@ if(WINDOWS)
 
     # Filenames are different for 32/64 bit BugSplat file and we don't
     # have any control over them so need to branch.
-    if (BUGSPLAT_DB)
+    if (USE_BUGSPLAT)
       if(ADDRESS_SIZE EQUAL 32)
         set(release_files ${release_files} BugSplat.dll)
         set(release_files ${release_files} BugSplatRc.dll)
@@ -60,7 +60,7 @@ if(WINDOWS)
         set(release_files ${release_files} BugSplatRc64.dll)
         set(release_files ${release_files} BsSndRpt64.exe)
       endif(ADDRESS_SIZE EQUAL 32)
-    endif (BUGSPLAT_DB)
+    endif (USE_BUGSPLAT)
 
     if (FMODEX)
 
diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake
index b3f42c1a5e9..fa10a9d4437 100644
--- a/indra/cmake/LLAddBuildTest.cmake
+++ b/indra/cmake/LLAddBuildTest.cmake
@@ -2,6 +2,7 @@
 include(00-Common)
 include(LLTestCommand)
 include(GoogleMock)
+include(bugsplat)
 include(Tut)
 
 #*****************************************************************************
@@ -22,7 +23,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources)
   # there is another branch that will conflict heavily with any changes here.
 INCLUDE(GoogleMock)
 
-
   IF(LL_TEST_VERBOSE)
     MESSAGE("LL_ADD_PROJECT_UNIT_TESTS UNITTEST_PROJECT_${project} sources: ${sources}")
   ENDIF(LL_TEST_VERBOSE)
@@ -87,6 +87,12 @@ INCLUDE(GoogleMock)
     IF(LL_TEST_VERBOSE)
       MESSAGE("LL_ADD_PROJECT_UNIT_TESTS ${name}_test_SOURCE_FILES ${${name}_test_SOURCE_FILES}")
     ENDIF(LL_TEST_VERBOSE)
+
+    if (USE_BUGSPLAT)
+      SET_PROPERTY(SOURCE ${${name}_test_SOURCE_FILES}
+          APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+    endif (USE_BUGSPLAT)
+
     # Headers
     GET_OPT_SOURCE_FILE_PROPERTY(${name}_test_additional_HEADER_FILES ${source} LL_TEST_ADDITIONAL_HEADER_FILES)
     SET(${name}_test_HEADER_FILES ${name}.h ${${name}_test_additional_HEADER_FILES})
@@ -223,6 +229,11 @@ FUNCTION(LL_ADD_INTEGRATION_TEST
     SET_TARGET_PROPERTIES(INTEGRATION_TEST_${testname} PROPERTIES COMPILE_FLAGS -I"${TUT_INCLUDE_DIR}")
   endif(USESYSTEMLIBS)
 
+  if (USE_BUGSPLAT)
+      SET_PROPERTY(SOURCE ${source_files}
+          APPEND PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+  endif (USE_BUGSPLAT)
+
   # The following was copied to llcorehttp/CMakeLists.txt's texture_load target. 
   # Any changes made here should be replicated there.
   if (WINDOWS)
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index a5770c5528d..c81b22e572d 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -34,7 +34,6 @@ set(LL_TESTS ON CACHE BOOL "Build and run unit and integration tests (disable fo
 set(INCREMENTAL_LINK OFF CACHE BOOL "Use incremental linking on win32 builds (enable for faster links on some machines)")
 set(ENABLE_MEDIA_PLUGINS ON CACHE BOOL "Turn off building media plugins if they are imported by third-party library mechanism")
 set(VIEWER_SYMBOL_FILE "" CACHE STRING "Name of tarball into which to place symbol files")
-set(BUGSPLAT_DB "" CACHE STRING "BugSplat database name, if BugSplat crash reporting is desired")
 
 if(LIBS_CLOSED_DIR)
   file(TO_CMAKE_PATH "${LIBS_CLOSED_DIR}" LIBS_CLOSED_DIR)
diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake
index 59644b73ce1..749ea054039 100644
--- a/indra/cmake/bugsplat.cmake
+++ b/indra/cmake/bugsplat.cmake
@@ -1,25 +1,32 @@
-# BugSplat is engaged by setting BUGSPLAT_DB to the target BugSplat database
-# name.
-if (BUGSPLAT_DB)
-  if (USESYSTEMLIBS)
-    message(STATUS "Looking for system BugSplat")
-    set(BUGSPLAT_FIND_QUIETLY ON)
-    set(BUGSPLAT_FIND_REQUIRED ON)
-    include(FindBUGSPLAT)
-  else (USESYSTEMLIBS)
-    message(STATUS "Engaging autobuild BugSplat")
-    include(Prebuilt)
-    use_prebuilt_binary(bugsplat)
-    if (WINDOWS)
-      set(BUGSPLAT_LIBRARIES 
-        ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
-        )
-    elseif (DARWIN)
-      find_library(BUGSPLAT_LIBRARIES BugsplatMac
-        PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
-    else (WINDOWS)
+if (INSTALL_PROPRIETARY)
+    set(USE_BUGSPLAT ON  CACHE BOOL "Use the BugSplat crash reporting system")
+else (INSTALL_PROPRIETARY)
+    set(USE_BUGSPLAT OFF CACHE BOOL "Use the BugSplat crash reporting system")
+endif (INSTALL_PROPRIETARY)
+
+if (USE_BUGSPLAT)
+    if (NOT USESYSTEMLIBS)
+        include(Prebuilt)
+        use_prebuilt_binary(bugsplat)
+        if (WINDOWS)
+            set(BUGSPLAT_LIBRARIES 
+                ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib
+                )
+        elseif (DARWIN)
+            find_library(BUGSPLAT_LIBRARIES BugsplatMac
+                PATHS "${ARCH_PREBUILT_DIRS_RELEASE}")
+        else (WINDOWS)
+            message(FATAL_ERROR "BugSplat is not supported; add -DUSE_BUGSPLAT=OFF")
+        endif (WINDOWS)
+    else (NOT USESYSTEMLIBS)
+        set(BUGSPLAT_FIND_QUIETLY ON)
+        set(BUGSPLAT_FIND_REQUIRED ON)
+        include(FindBUGSPLAT)
+    endif (NOT USESYSTEMLIBS)
+
+    set(BUGSPLAT_DB "" CACHE STRING "BugSplat crash database name")
 
-    endif (WINDOWS)
     set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat)
-  endif (USESYSTEMLIBS)
-endif (BUGSPLAT_DB)
+    set(BUGSPLAT_DEFINE "LL_BUGSPLAT")
+endif (USE_BUGSPLAT)
+
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index af41b9e460c..e3afa5eca4c 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -5,6 +5,7 @@ project(llcommon)
 
 include(00-Common)
 include(LLCommon)
+include(bugsplat)
 include(Linking)
 include(Boost)
 include(LLSharedLibs)
@@ -257,10 +258,10 @@ set(llcommon_HEADER_FILES
 set_source_files_properties(${llcommon_HEADER_FILES}
                             PROPERTIES HEADER_FILE_ONLY TRUE)
 
-if (BUGSPLAT_DB)
-  set_source_files_properties(llapp.cpp
-    PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT")
-endif (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
+  set_source_files_properties(${llcommon_SOURCE_FILES}
+    PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
 
 list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES})
 
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 0ddce353f16..77d7fe1b24c 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -25,6 +25,7 @@
  * $/LicenseInfo$
  */
 
+#define _LLERROR_CPP_
 #include "linden_common.h"
 
 #include "llerror.h"
@@ -724,7 +725,7 @@ namespace LLError
 		s->mCrashFunction = fatal_function;
 	}
 
-	void restoreCrashOnError()
+    void restoreCrashOnError()
 	{
 		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();
 		s->mCrashFunction = NULL;
@@ -1310,7 +1311,7 @@ namespace LLError
 		LLMutexTrylock lock(&gLogMutex,5);
 		if (!lock.isLocked())
 		{
-			return true;
+			return false; // because this wasn't logged, it cannot be fatal
 		}
 
 		// If we hit a logging request very late during shutdown processing,
@@ -1318,7 +1319,7 @@ namespace LLError
 		// DO NOT resurrect them.
 		if (Settings::wasDeleted() || Globals::wasDeleted())
 		{
-			return true;
+            return false; // because this wasn't logged, it cannot be fatal
 		}
 
 		Globals* g = Globals::getInstance();
@@ -1352,7 +1353,7 @@ namespace LLError
 				} 
 				else
 				{
-					return true;
+					return false; // because this wasn't logged, it cannot be fatal
 				}
 			}
 			else 
@@ -1372,11 +1373,17 @@ namespace LLError
             if (s->mCrashFunction)
             {
                 s->mCrashFunction(message);
-                return false;
+                return false; // because an override is in effect
+            }
+            else
+            {
+                return true; // calling macro should crash
             }
 		}
-
-        return true;
+        else
+        {
+            return false; // not ERROR, so do not crash
+        }
 	}
 }
 
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index cbade88f611..07aa5c6f8b4 100644
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -202,7 +202,7 @@ namespace LLError
 
 		static void flush(std::ostringstream* out, char* message);
 
-        // returns false iff there is a fatal crash override in effect
+        // returns false iff the calling macro should crash
 		static bool flush(std::ostringstream*, const CallSite&);
 
 		static std::string demangle(const char* mangled);
@@ -371,18 +371,22 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;
 
 #define LL_NEWLINE '\n'
 
+#ifdef _LLERROR_CPP_
+volatile int* gCauseCrash = NULL;
+#else
+volatile extern int* gCauseCrash;
+#endif // _LLERROR_CPP_
+
 // Use this only in LL_ERRS or in a place that LL_ERRS may not be used
-#define LLERROR_CRASH         \
-{                             \
-    int* make_me_crash = NULL;\
-    *make_me_crash = 0;       \
-    exit(*make_me_crash);     \
+#define LLERROR_CRASH       \
+{                           \
+    *gCauseCrash = 0;       \
+    exit(*gCauseCrash);     \
 }
 
 #define LL_ENDL                                          \
 			LLError::End();                              \
-            if (LLError::Log::flush(_out, _site)         \
-                && _site.mLevel == LLError::LEVEL_ERROR) \
+            if (LLError::Log::flush(_out, _site))        \
                 LLERROR_CRASH                            \
         }                                                \
 	} while(0)
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index 7ca6ddb7378..af46430f74b 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -92,11 +92,19 @@ namespace LLError
 	/*
 		Control functions.
 	*/
+
 	typedef boost::function<void(const std::string&)> FatalFunction;
 
-    LL_COMMON_API void overrideCrashOnError(const FatalFunction&);
-    LL_COMMON_API void restoreCrashOnError();
-    
+	/// Override the default behavior of crashing on LL_ERRS; this should NEVER be used except in test code
+	LL_COMMON_API void overrideCrashOnError(const FatalFunction&);
+		// The fatal function will be called when an message of LEVEL_ERROR
+		// is logged.  Note: supressing a LEVEL_ERROR message from being logged
+		// (by, for example, setting a class level to LEVEL_NONE), will keep
+		// the that message from causing the fatal funciton to be invoked.
+
+    /// Undo the effect of the overrideCrashOnError above
+	LL_COMMON_API void restoreCrashOnError();
+
 	LL_COMMON_API std::string getFatalMessage();
 		// Retrieve the message last passed to LL_ERRS, if any
 
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index f7bfa36bb5c..bf20c87c898 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -59,6 +59,7 @@ class LLLeapImpl: public LLLeap
         // pump name -- so it should NOT need tweaking for uniqueness.
         mReplyPump(LLUUID::generateNewID().asString()),
         mExpect(0),
+
         // Instantiate a distinct LLLeapListener for this plugin. (Every
         // plugin will want its own collection of managed listeners, etc.)
         // Pass it a callback to our connect() method, so it can send events
@@ -144,9 +145,6 @@ class LLLeapImpl: public LLLeap
         mStderrConnection = childerr.getPump()
             .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));
 
-        // For our lifespan, intercept any LL_ERRS so we can notify plugin
-        LLError::overrideCrashOnError(boost::bind(&LLLeapImpl::fatalFunction, this, _1));
-
         // Send child a preliminary event reporting our own reply-pump name --
         // which would otherwise be pretty tricky to guess!
         wstdin(mReplyPump.getName(),
@@ -161,8 +159,6 @@ class LLLeapImpl: public LLLeap
     virtual ~LLLeapImpl()
     {
         LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL;
-        // Restore original fatal crash behavior for LL_ERRS
-        LLError::restoreCrashOnError();
     }
 
     // Listener for failed launch attempt
@@ -376,30 +372,6 @@ class LLLeapImpl: public LLLeap
         return false;
     }
 
-    void fatalFunction(const std::string& error)
-    {
-        // Notify plugin
-        LLSD event;
-        event["type"] = "error";
-        event["error"] = error;
-        mReplyPump.post(event);
-
-        // All the above really accomplished was to buffer the serialized
-        // event in our WritePipe. Have to pump mainloop a couple times to
-        // really write it out there... but time out in case we can't write.
-        LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN));
-        LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
-        LLSD nop;
-        F64 until = (LLTimer::getElapsedSeconds() + 2).value();
-        while (childin.size() && LLTimer::getElapsedSeconds() < until)
-        {
-            mainloop.post(nop);
-        }
-
-        // go ahead and do the crash that LLError would have done
-        LLERROR_CRASH
-    }
-
 private:
     /// We always want to listen on mReplyPump with wstdin(); under some
     /// circumstances we'll also echo other LLEventPumps to the plugin.
diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h
index b2802714768..fedc17dbe96 100644
--- a/indra/llcommon/tests/wrapllerrs.h
+++ b/indra/llcommon/tests/wrapllerrs.h
@@ -50,11 +50,11 @@ extern void wouldHaveCrashed(const std::string& message);
 
 struct WrapLLErrs
 {
-    WrapLLErrs():
+    WrapLLErrs()
         // Resetting Settings discards the default Recorder that writes to
         // stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the
         // console output of successful tests, potentially confusing things.
-        mPriorErrorSettings(LLError::saveAndResetSettings())
+    :mPriorErrorSettings(LLError::saveAndResetSettings())
     {
         // Make LL_ERRS call our own operator() method
         LLError::overrideCrashOnError(boost::bind(&WrapLLErrs::operator(), this, _1));
@@ -210,6 +210,7 @@ class CaptureLog : public boost::noncopyable
     {
         LLError::removeRecorder(mRecorder);
         LLError::restoreSettings(mOldSettings);
+        LLError::restoreCrashOnError();
     }
 
     /// Don't assume the message we want is necessarily the LAST log message
diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt
index 9dbc6f447ec..286c275b905 100644
--- a/indra/llcorehttp/CMakeLists.txt
+++ b/indra/llcorehttp/CMakeLists.txt
@@ -13,6 +13,7 @@ include(LLAddBuildTest)
 include(LLMessage)
 include(LLCommon)
 include(Tut)
+include(bugsplat)
 
 include_directories (${CMAKE_CURRENT_SOURCE_DIR})
 
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 293ada7548e..28b8e8c06d8 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -11,6 +11,7 @@ include(LLKDU)
 include(LLImageJ2COJ)
 include(ZLIB)
 include(LLAddBuildTest)
+include(bugsplat)
 include(Tut)
 
 include_directories(
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index 379c3ee9eaf..625459823c2 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -4,6 +4,7 @@ project(llmath)
 
 include(00-Common)
 include(LLCommon)
+include(bugsplat)
 include(Boost)
 
 include_directories(
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 04f6c9b7f0b..bbfa8388274 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -8,9 +8,7 @@ include(00-Common)
 include(Linking)
 
 include(Boost)
-if (BUGSPLAT_DB)
-  include(bugsplat)
-endif (BUGSPLAT_DB)
+include(bugsplat)
 include(BuildPackagesInfo)
 include(BuildVersion)
 include(CMakeCopyIfDifferent)
@@ -97,18 +95,18 @@ include_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}
     )
 
-if (BUGSPLAT_DB)
-  include_directories(
-    ${BUGSPLAT_INCLUDE_DIR}
-    )
-endif (BUGSPLAT_DB)
-
 include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
     ${LLXML_SYSTEM_INCLUDE_DIRS}
     ${LLPHYSICSEXTENSIONS_INCLUDE_DIRS}
     )
 
+if (USE_BUGSPLAT)
+  include_directories(AFTER
+    ${BUGSPLAT_INCLUDE_DIR}
+    )
+endif (USE_BUGSPLAT)
+
 set(viewer_SOURCE_FILES
     groupchatlistener.cpp
     llaccountingcostmanager.cpp
@@ -1390,11 +1388,11 @@ if (DARWIN)
     ${COREAUDIO_LIBRARY}
     )
 
-  if (BUGSPLAT_DB)
+  if (USE_BUGSPLAT)
     list(APPEND viewer_LIBRARIES
       ${BUGSPLAT_LIBRARIES}
       )
-  endif (BUGSPLAT_DB)
+  endif (USE_BUGSPLAT)
 
   # Add resource files to the project.
   set(viewer_RESOURCE_FILES
@@ -1729,10 +1727,10 @@ if (SDL_FOUND)
     )
 endif (SDL_FOUND)
 
-if (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
   set_property(TARGET ${VIEWER_BINARY_NAME}
     PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT")
-endif (BUGSPLAT_DB)
+endif (USE_BUGSPLAT)
 
 # add package files
 file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST
@@ -2018,11 +2016,11 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${LLAPPEARANCE_LIBRARIES}
     )
 
-if (BUGSPLAT_DB)
+if (USE_BUGSPLAT)
   target_link_libraries(${VIEWER_BINARY_NAME}
     ${BUGSPLAT_LIBRARIES}
     )
-endif (BUGSPLAT_DB)
+endif (USE_BUGSPLAT)
 
 set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
     "Path to artwork files.")
@@ -2206,7 +2204,7 @@ endif (INSTALL)
 
 # Note that the conventional VIEWER_SYMBOL_FILE is set by ../../build.sh
 if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIEWER_SYMBOL_FILE)
-  if (NOT BUGSPLAT_DB)
+  if (NOT USE_BUGSPLAT)
     # Breakpad symbol-file generation
     set(SYMBOL_SEARCH_DIRS "")
     if (WINDOWS)
@@ -2261,7 +2259,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
       add_dependencies(generate_symbols "${VIEWER_COPY_MANIFEST}")
     endif (WINDOWS OR LINUX)
 
-  else (NOT BUGSPLAT_DB)
+  else (NOT USE_BUGSPLAT)
     # BugSplat symbol-file generation
     if (WINDOWS)
       # Just pack up a tarball containing only the .pdb file for the
@@ -2345,9 +2343,9 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE
     if (LINUX)
       # TBD
     endif (LINUX)
-  endif (NOT BUGSPLAT_DB)
+  endif (NOT USE_BUGSPLAT)
 
-  # for both BUGSPLAT_DB and Breakpad
+  # for both Bugsplat and Breakpad
   add_dependencies(llpackage generate_symbols)
 endif ()
 
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 1fda07edd65..f9ee22d20a7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -719,14 +719,14 @@ LLAppViewer::LLAppViewer()
 	// from the previous viewer run between this constructor call and the
 	// init() call, which will overwrite the static_debug_info.log file for
 	// THIS run. So setDebugFileNames() early.
-#if LL_BUGSPLAT
+#   ifdef LL_BUGSPLAT
 	// MAINT-8917: don't create a dump directory just for the
 	// static_debug_info.log file
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
-#else // ! LL_BUGSPLAT
+#   else // ! LL_BUGSPLAT
 	// write Google Breakpad minidump files to a per-run dump directory to avoid multiple viewer issues.
 	std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_DUMP, "");
-#endif // ! LL_BUGSPLAT
+#   endif // ! LL_BUGSPLAT
 	mDumpPath = logdir;
 	setMiniDumpDir(logdir);
 	setDebugFileNames(logdir);
@@ -751,6 +751,16 @@ class LLUITranslationBridge : public LLTranslationBridge
 	}
 };
 
+namespace {
+// With Xcode 6, _exit() is too magical to use with boost::bind(), so provide
+// this little helper function.
+void fast_exit(int rc)
+{
+	_exit(rc);
+}
+
+
+}
 
 bool LLAppViewer::init()
 {
@@ -790,6 +800,18 @@ bool LLAppViewer::init()
 	initMaxHeapSize() ;
 	LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize"));
 
+	// Although initLoggingAndGetLastDuration() is the right place to mess with
+	// overrideCrashOnError(), we can't query gSavedSettings until after
+	// initConfiguration().
+	S32 rc(gSavedSettings.getS32("QAModeTermCode"));
+	if (rc >= 0)
+	{
+		// QAModeTermCode set, terminate with that rc on LL_ERRS. Use
+		// fast_exit() rather than exit() because normal cleanup depends too
+		// much on successful startup!
+		LLError::overrideCrashOnError(boost::bind(fast_exit, rc));
+	}
+
     mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
 
 	// Initialize the non-LLCurl libcurl library.  Should be called
@@ -2096,9 +2118,6 @@ bool LLAppViewer::cleanup()
 	return true;
 }
 
-	gDebugInfo["FatalMessage"] = error_string;
-	LLAppViewer::instance()->writeDebugInfo();
-
 bool LLAppViewer::initThreads()
 {
 	static const bool enable_threads = true;
@@ -2133,6 +2152,24 @@ bool LLAppViewer::initThreads()
 	return true;
 }
 
+#ifndef LL_BUGSPLAT
+void errorCallback(const std::string &error_string)
+{
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+	OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
+#endif
+
+	//Set the ErrorActivated global so we know to create a marker file
+	gLLErrorActivated = true;
+
+	gDebugInfo["FatalMessage"] = error_string;
+	// We're not already crashing -- we simply *intend* to crash. Since we
+	// haven't actually trashed anything yet, we can afford to write the whole
+	// static info file.
+	LLAppViewer::instance()->writeDebugInfo();
+}
+#endif // ! LL_BUGSPLAT
+
 void LLAppViewer::initLoggingAndGetLastDuration()
 {
 	//
@@ -2889,7 +2926,6 @@ bool LLAppViewer::initWindow()
 	// Need to load feature table before cheking to start watchdog.
 	bool use_watchdog = false;
 	int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
-
 	if (watchdog_enabled_setting == -1)
 	{
 		use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
@@ -3352,10 +3388,19 @@ void LLAppViewer::writeSystemInfo()
 	gDebugInfo["MainloopThreadID"] = (S32)thread_id;
 #endif
 
+#ifndef LL_BUGSPLAT
+	// "CrashNotHandled" is set here, while things are running well,
+	// in case of a freeze. If there is a freeze, the crash logger will be launched
+	// and can read this value from the debug_info.log.
+	// If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
+	// then the value of "CrashNotHandled" will be set to true.
+	gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
+#else // LL_BUGSPLAT
 	// "CrashNotHandled" is obsolete; it used (not very successsfully)
     // to try to distinguish crashes from freezes
 	gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false;
     gDebugInfo["FatalMessage"] = LLError::getFatalMessage();
+#endif // ! LL_BUGSPLAT
 
 	// Insert crash host url (url to post crash log to) if configured. This insures
 	// that the crash report will go to the proper location in the case of a
diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp
index 2f3e5db84fe..0a011132246 100644
--- a/indra/newview/llwatchdog.cpp
+++ b/indra/newview/llwatchdog.cpp
@@ -145,10 +145,10 @@ void LLWatchdogTimeout::ping(const std::string& state)
 }
 
 // LLWatchdog
-LLWatchdog::LLWatchdog() :
-	mSuspectsAccessMutex(),
-	mTimer(NULL),
-	mLastClockCount(0)
+LLWatchdog::LLWatchdog()
+    :mSuspectsAccessMutex()
+    ,mTimer(NULL)
+	,mLastClockCount(0)
 {
 }
 
diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt
index 8344cead57c..7ac1f1db23d 100644
--- a/indra/test/CMakeLists.txt
+++ b/indra/test/CMakeLists.txt
@@ -13,7 +13,7 @@ include(LLXML)
 include(Linking)
 include(Tut)
 include(LLAddBuildTest)
-
+include(bugsplat)
 include(GoogleMock)
 
 include_directories(
@@ -82,6 +82,10 @@ list(APPEND test_SOURCE_FILES ${test_HEADER_FILES})
 
 add_executable(lltest ${test_SOURCE_FILES})
 
+if (USE_BUGSPLAT)
+  set_target_properties(lltest PROPERTIES COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}")
+endif (USE_BUGSPLAT)
+
 target_link_libraries(lltest
     ${LLDATABASE_LIBRARIES}
     ${LLINVENTORY_LIBRARIES}
diff --git a/indra/test/test.cpp b/indra/test/test.cpp
index 125de72b793..5dabcbbc584 100644
--- a/indra/test/test.cpp
+++ b/indra/test/test.cpp
@@ -75,7 +75,10 @@
 
 #include <fstream>
 
-void wouldHaveCrashed(const std::string& message);
+void wouldHaveCrashed(const std::string& message)
+{
+	tut::fail("fatal error message: " + message);
+}
 
 namespace tut
 {
@@ -506,11 +509,6 @@ void stream_groups(std::ostream& s, const char* app)
 	}
 }
 
-void wouldHaveCrashed(const std::string& message)
-{
-	tut::fail("fatal error message: " + message);
-}
-
 static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL;
 
 int main(int argc, char **argv)
-- 
GitLab