diff options
| author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2021-05-21 20:31:53 +0300 | 
|---|---|---|
| committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2021-05-21 20:31:53 +0300 | 
| commit | 2922c593160f81d19f39d80fc84a25c2a0e0d8aa (patch) | |
| tree | 7b5c5aa2889cb2e7d746d54a6ec9778cc7c77480 /indra | |
| parent | 646cde231d72fb217c6d34cd95d941a24544ca3a (diff) | |
| parent | 24501dfa0ee3fd6f5755deb1bc5261cd297a2bc7 (diff) | |
Merge branch 'sl-10297' into DRTVWR-516-maint
Diffstat (limited to 'indra')
32 files changed, 496 insertions, 565 deletions
| diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 53e5d7b6a5..db88e44127 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)  set(LEGACY_STDIO_LIBS) @@ -50,7 +51,10 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts)  add_custom_target(viewer) +if (NOT USE_BUGSPLAT)  add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) +endif (NOT USE_BUGSPLAT) +  add_subdirectory(${LIBS_OPEN_PREFIX}llplugin)  add_subdirectory(${LIBS_OPEN_PREFIX}llui)  add_subdirectory(${LIBS_OPEN_PREFIX}viewer_components) @@ -64,29 +68,18 @@ add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins)  endif (ENABLE_MEDIA_PLUGINS)  if (LINUX) -  add_subdirectory(${VIEWER_PREFIX}linux_crash_logger)    if (INSTALL_PROPRIETARY)        include(LLAppearanceUtility)        add_subdirectory(${LLAPPEARANCEUTILITY_SRC_DIR} ${LLAPPEARANCEUTILITY_BIN_DIR})    endif (INSTALL_PROPRIETARY) -  add_dependencies(viewer linux-crash-logger-strip-target) -elseif (DARWIN) -  add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) -  add_dependencies(viewer mac-crash-logger) -elseif (WINDOWS) -  add_subdirectory(${VIEWER_PREFIX}win_crash_logger) -  # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake -  if (EXISTS ${VIEWER_DIR}win_setup) -    add_subdirectory(${VIEWER_DIR}win_setup) -  endif (EXISTS ${VIEWER_DIR}win_setup) -  # add_dependencies(viewer windows-setup windows-crash-logger) -  add_dependencies(viewer windows-crash-logger)  endif (LINUX) -add_subdirectory(${VIEWER_PREFIX}newview) -add_dependencies(viewer secondlife-bin) - -add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) +if (WINDOWS) +    # cmake EXISTS requires an absolute path, see indra/cmake/Variables.cmake +    if (EXISTS ${VIEWER_DIR}win_setup) +      add_subdirectory(${VIEWER_DIR}win_setup) +    endif (EXISTS ${VIEWER_DIR}win_setup) +endif (WINDOWS)  # sets the 'startup project' for debugging from visual studio.  set_property( @@ -94,6 +87,32 @@ 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") +    if (LINUX) +      add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) +      add_dependencies(viewer linux-crash-logger-strip-target) +    elseif (DARWIN) +      add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) +      add_dependencies(viewer mac-crash-logger) +    elseif (WINDOWS) +      add_subdirectory(${VIEWER_PREFIX}win_crash_logger) +      # add_dependencies(viewer windows-setup windows-crash-logger) +      add_dependencies(viewer windows-crash-logger) +    endif (LINUX) +endif (USE_BUGSPLAT) + +add_subdirectory(${VIEWER_PREFIX}newview) +add_dependencies(viewer secondlife-bin) + +add_subdirectory(${VIEWER_PREFIX}doxygen EXCLUDE_FROM_ALL) +  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 de81512eef..46ddb9d15b 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -66,7 +66,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) @@ -76,7 +76,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 (FMODSTUDIO)          set(debug_files ${debug_files} fmodL.dll) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 4932e9044f..4937c2a9d7 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}) @@ -224,6 +230,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 a5770c5528..c81b22e572 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 59644b73ce..5f5cc51f63 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 REQUIRED +                NO_DEFAULT_PATH 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/linux_crash_logger/README.txt b/indra/linux_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/linux_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index cecfadcd91..dd266630ea 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -4,6 +4,7 @@ project(llcommon)  include(00-Common)  include(LLCommon) +include(bugsplat)  include(Linking)  include(Boost)  include(LLSharedLibs) @@ -260,10 +261,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/llapp.cpp b/indra/llcommon/llapp.cpp index a90b294550..6064a843ae 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -528,7 +528,12 @@ void LLApp::setupErrorHandling(bool second_instance)  #endif // LL_LINUX  #endif // ! LL_WINDOWS + +#ifdef LL_BUGSPLAT +    // do not start our own error thread +#else // ! LL_BUGSPLAT  	startErrorThread(); +#endif  }  void LLApp::startErrorThread() @@ -808,7 +813,9 @@ void setup_signals()  	act.sa_flags = SA_SIGINFO;  	// Synchronous signals +#   ifndef LL_BUGSPLAT  	sigaction(SIGABRT, &act, NULL); +#   endif  	sigaction(SIGALRM, &act, NULL);  	sigaction(SIGBUS, &act, NULL);  	sigaction(SIGFPE, &act, NULL); @@ -845,7 +852,9 @@ void clear_signals()  	act.sa_flags = SA_SIGINFO;  	// Synchronous signals +#   ifndef LL_BUGSPLAT  	sigaction(SIGABRT, &act, NULL); +#   endif  	sigaction(SIGALRM, &act, NULL);  	sigaction(SIGBUS, &act, NULL);  	sigaction(SIGFPE, &act, NULL); @@ -898,6 +907,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)  		return;  	case SIGABRT: +        // Note that this handler is not set for SIGABRT when using Bugsplat  		// Abort just results in termination of the app, no funky error handling.  		if (LLApp::sLogInSignal)  		{ diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index f876b8ee4a..8355df9045 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -442,8 +442,6 @@ namespace      protected:  		Globals();  	public: -		std::ostringstream messageStream; -		bool messageStreamInUse;  		std::string mFatalMessage;  		void addCallSite(LLError::CallSite&); @@ -453,12 +451,7 @@ namespace  		CallSiteVector callSites;  	}; -	Globals::Globals() -		: messageStream(), -		messageStreamInUse(false), -		callSites() -	{ -	} +	Globals::Globals() {}      Globals* Globals::getInstance()      { @@ -549,7 +542,7 @@ namespace LLError  		mFileLevelMap(),  		mTagLevelMap(),  		mUniqueLogMessages(), -		mCrashFunction(NULL), +		mCrashFunction([](const std::string&){}),  		mTimeFunction(NULL),  		mRecorders(),  		mShouldLogCallCounter(0) @@ -728,7 +721,6 @@ namespace  		LLError::setDefaultLevel(LLError::LEVEL_INFO);  		LLError::setAlwaysFlush(true);  		LLError::setEnabledLogTypesMask(0xFFFFFFFF); -		LLError::setFatalFunction(LLError::crashAndLoop);  		LLError::setTimeFunction(LLError::utcTime);  		// log_to_stderr is only false in the unit and integration tests to keep builds quieter @@ -1360,57 +1352,7 @@ namespace LLError  	} -	std::ostringstream* Log::out() -	{ -		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); - -		if (lock.isLocked()) -		{ -			Globals* g = Globals::getInstance(); - -			if (!g->messageStreamInUse) -			{ -				g->messageStreamInUse = true; -				return &g->messageStream; -			} -		} - -		return new std::ostringstream; -	} - -	void Log::flush(std::ostringstream* out, char* message) -	{ -		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); -		if (!lock.isLocked()) -		{ -			return; -		} - -		if(strlen(out->str().c_str()) < 128) -		{ -			strcpy(message, out->str().c_str()); -		} -		else -		{ -			strncpy(message, out->str().c_str(), 127); -			message[127] = '\0' ; -		} - -		Globals* g = Globals::getInstance(); -		if (out == &g->messageStream) -		{ -			g->messageStream.clear(); -			g->messageStream.str(""); -			g->messageStreamInUse = false; -		} -		else -		{ -			delete out; -		} -		return ; -	} - -	void Log::flush(std::ostringstream* out, const CallSite& site) +	void Log::flush(const std::ostringstream& out, const CallSite& site)  	{  		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);  		if (!lock.isLocked()) @@ -1421,22 +1363,11 @@ namespace LLError  		Globals* g = Globals::getInstance();  		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		std::string message = out->str(); -		if (out == &g->messageStream) -		{ -			g->messageStream.clear(); -			g->messageStream.str(""); -			g->messageStreamInUse = false; -		} -		else -		{ -			delete out; -		} - +		std::string message = out.str();  		if (site.mPrintOnce)  		{ -            std::ostringstream message_stream; +			std::ostringstream message_stream;  			std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);  			if (messageIter != s->mUniqueLogMessages.end()) @@ -1457,8 +1388,8 @@ namespace LLError  				message_stream << "ONCE: ";  				s->mUniqueLogMessages[message] = 1;  			} -            message_stream << message; -            message = message_stream.str(); +			message_stream << message; +			message = message_stream.str();  		}  		writeToRecorders(site, message); @@ -1466,10 +1397,7 @@ namespace LLError  		if (site.mLevel == LEVEL_ERROR)  		{  			g->mFatalMessage = message; -			if (s->mCrashFunction) -			{ -				s->mCrashFunction(message); -			} +			s->mCrashFunction(message);  		}  	}  } @@ -1533,29 +1461,6 @@ namespace LLError  		return s->mShouldLogCallCounter;  	} -#if LL_WINDOWS -		// VC80 was optimizing the error away. -		#pragma optimize("", off) -#endif -	void crashAndLoop(const std::string& message) -	{ -		// Now, we go kaboom! -		int* make_me_crash = NULL; - -		*make_me_crash = 0; - -		while(true) -		{ -			// Loop forever, in case the crash didn't work? -		} -		 -		// this is an attempt to let Coverity and other semantic scanners know that this function won't be returning ever. -		exit(EXIT_FAILURE); -	} -#if LL_WINDOWS -		#pragma optimize("", on) -#endif -  	std::string utcTime()  	{  		time_t now = time(NULL); @@ -1572,33 +1477,7 @@ namespace LLError  namespace LLError  {      -	char** LLCallStacks::sBuffer = NULL ; -	S32    LLCallStacks::sIndex  = 0 ; - -	//static -    void LLCallStacks::allocateStackBuffer() -    { -        if(sBuffer == NULL) -        { -            sBuffer = new char*[512] ; -            sBuffer[0] = new char[512 * 128] ; -            for(S32 i = 1 ; i < 512 ; i++) -            { -                sBuffer[i] = sBuffer[i-1] + 128 ; -            } -            sIndex = 0 ; -        } -    } - -    void LLCallStacks::freeStackBuffer() -    { -        if(sBuffer != NULL) -        { -            delete [] sBuffer[0] ; -            delete [] sBuffer ; -            sBuffer = NULL ; -        } -    } +    LLCallStacks::StringVector LLCallStacks::sBuffer ;      //static      void LLCallStacks::push(const char* function, const int line) @@ -1609,33 +1488,24 @@ namespace LLError              return;          } -        if(sBuffer == NULL) -        { -            allocateStackBuffer(); -        } - -        if(sIndex > 511) +        if(sBuffer.size() > 511)          {              clear() ;          } -        strcpy(sBuffer[sIndex], function) ; -        sprintf(sBuffer[sIndex] + strlen(function), " line: %d ", line) ; -        sIndex++ ; - -        return ; +        std::ostringstream out; +        insert(out, function, line); +        sBuffer.push_back(out.str());      }      //static -    std::ostringstream* LLCallStacks::insert(const char* function, const int line) +    void LLCallStacks::insert(std::ostream& out, const char* function, const int line)      { -        std::ostringstream* _out = LLError::Log::out(); -        *_out << function << " line " << line << " " ; -        return _out ; +        out << function << " line " << line << " " ;      }      //static -    void LLCallStacks::end(std::ostringstream* _out) +    void LLCallStacks::end(const std::ostringstream& out)      {          LLMutexTrylock lock(getMutex<STACKS_MUTEX>(), 5);          if (!lock.isLocked()) @@ -1643,17 +1513,12 @@ namespace LLError              return;          } -        if(sBuffer == NULL) -        { -            allocateStackBuffer(); -        } - -        if(sIndex > 511) +        if(sBuffer.size() > 511)          {              clear() ;          } -        LLError::Log::flush(_out, sBuffer[sIndex++]) ; +        sBuffer.push_back(out.str());      }      //static @@ -1665,33 +1530,30 @@ namespace LLError              return;          } -        if(sIndex > 0) +        if(! sBuffer.empty())          {              LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; -            while(sIndex > 0) +            for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend()); +                 ri != re; ++ri)              {                   -                sIndex-- ; -                LL_INFOS() << sBuffer[sIndex] << LL_ENDL; +                LL_INFOS() << (*ri) << LL_ENDL;              }              LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;          } -        if(sBuffer != NULL) -        { -            freeStackBuffer(); -        } +        cleanup();      }      //static      void LLCallStacks::clear()      { -        sIndex = 0 ; +        sBuffer.clear();      }      //static      void LLCallStacks::cleanup()      { -        freeStackBuffer(); +        clear();      }      std::ostream& operator<<(std::ostream& out, const LLStacktrace&) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index ffaa464d77..d439136ca8 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -29,7 +29,9 @@  #define LL_LLERROR_H  #include <sstream> +#include <string>  #include <typeinfo> +#include <vector>  #include "stdtypes.h" @@ -198,9 +200,7 @@ namespace LLError  	{  	public:  		static bool shouldLog(CallSite&); -		static std::ostringstream* out(); -		static void flush(std::ostringstream* out, char* message); -		static void flush(std::ostringstream*, const CallSite&); +		static void flush(const std::ostringstream&, const CallSite&);  		static std::string demangle(const char* mangled);  		/// classname<TYPE>()  		template <typename T> @@ -281,18 +281,15 @@ namespace LLError      class LL_COMMON_API LLCallStacks      {      private: -        static char**  sBuffer ; -        static S32     sIndex ; - -        static void allocateStackBuffer(); -        static void freeStackBuffer(); +        typedef std::vector<std::string> StringVector; +        static StringVector sBuffer ;      public:             static void push(const char* function, const int line) ; -        static std::ostringstream* insert(const char* function, const int line) ; +        static void insert(std::ostream& out, const char* function, const int line) ;          static void print() ;          static void clear() ; -        static void end(std::ostringstream* _out) ; +        static void end(const std::ostringstream& out) ;          static void cleanup();      }; @@ -306,10 +303,11 @@ namespace LLError  //this is cheaper than llcallstacks if no need to output other variables to call stacks.   #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) -#define llcallstacks                                                                      \ -	{                                                                                     \ -       std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \ -       (*_out) +#define llcallstacks                                                    \ +	{                                                                   \ +		std::ostringstream _out;                                        \ +		LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ;   \ +		_out  #define llcallstacksendl                   \  		LLError::End();                    \ @@ -355,11 +353,11 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;  		static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \  		lllog_test_() -#define lllog_test_()                                       \ -		if (LL_UNLIKELY(_site.shouldLog()))                 \ -		{                                                   \ -			std::ostringstream* _out = LLError::Log::out(); \ -			(*_out) +#define lllog_test_()                           \ +		if (LL_UNLIKELY(_site.shouldLog()))     \ +		{                                       \ +			std::ostringstream _out;            \ +			_out  #define lllog_site_args_(level, once, tags)                 \  	level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG),    \ @@ -378,15 +376,27 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;  //	LL_CONT << " for " << t << " seconds" << LL_ENDL;  //	  //Such computation is done iff the message will be logged. -#define LL_CONT	(*_out) +#define LL_CONT	_out  #define LL_NEWLINE '\n' -#define LL_ENDL                               \ -			LLError::End();                   \ -			LLError::Log::flush(_out, _site); \ -		}                                     \ -	} while(0) +// 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 LL_ENDL                                         \ +            LLError::End();                             \ +            LLError::Log::flush(_out, _site);           \ +            if (_site.mLevel == LLError::LEVEL_ERROR)   \ +            {                                           \ +                LLERROR_CRASH                           \ +            }                                           \ +        }                                               \ +    } while(0)  // NEW Macros for debugging, allow the passing of a string tag diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 25786d5457..e87bb7bf35 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -94,14 +94,16 @@ namespace LLError  	*/  	typedef boost::function<void(const std::string&)> FatalFunction; -	LL_COMMON_API void crashAndLoop(const std::string& message); -		// Default fatal function: access null pointer and loops forever  	LL_COMMON_API void setFatalFunction(const FatalFunction&); -		// The fatal function will be called when an message of LEVEL_ERROR +		// The fatal function will be called after 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. +		// that message from causing the fatal function to be invoked. +		// The passed FatalFunction will be the LAST log function called +		// before LL_ERRS crashes its caller. A FatalFunction can throw an +		// exception, or call exit(), to bypass the crash. It MUST disrupt the +		// flow of control because no caller expects LL_ERRS to return.  	LL_COMMON_API FatalFunction getFatalFunction();  		// Retrieve the previously-set FatalFunction @@ -147,14 +149,14 @@ namespace LLError  		virtual void recordMessage(LLError::ELevel, const std::string& message) = 0;  			// use the level for better display, not for filtering -        virtual bool enabled() { return true; } +		virtual bool enabled() { return true; }  		bool wantsTime();  		bool wantsTags();  		bool wantsLevel();  		bool wantsLocation();   		bool wantsFunctionName(); -        bool wantsMultiline(); +		bool wantsMultiline();  		void showTime(bool show);  		void showTags(bool show); @@ -165,15 +167,35 @@ namespace LLError  	protected:  		bool mWantsTime; -        bool mWantsTags; -        bool mWantsLevel; -        bool mWantsLocation; -        bool mWantsFunctionName; -        bool mWantsMultiline; +		bool mWantsTags; +		bool mWantsLevel; +		bool mWantsLocation; +		bool mWantsFunctionName; +		bool mWantsMultiline;  	};  	typedef boost::shared_ptr<Recorder> RecorderPtr; +    /** +     * Instantiate GenericRecorder with a callable(level, message) to get +     * control on every log message without having to code an explicit +     * Recorder subclass. +     */ +    template <typename CALLABLE> +    class GenericRecorder: public Recorder +    { +    public: +        GenericRecorder(const CALLABLE& callable): +            mCallable(callable) +        {} +        void recordMessage(LLError::ELevel level, const std::string& message) override +        { +            mCallable(level, message); +        } +    private: +        CALLABLE mCallable; +    }; +  	/**  	 * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership  	 * while still ensuring that the allocated memory is eventually freed @@ -181,6 +203,19 @@ namespace LLError  	LL_COMMON_API void addRecorder(RecorderPtr);  	LL_COMMON_API void removeRecorder(RecorderPtr);  		// each error message is passed to each recorder via recordMessage() +	/** +	 * Call addGenericRecorder() with a callable(level, message) to get +	 * control on every log message without having to code an explicit +	 * Recorder subclass. Save the returned RecorderPtr if you later want to +	 * call removeRecorder(). +	 */ +	template <typename CALLABLE> +	RecorderPtr addGenericRecorder(const CALLABLE& callable) +	{ +		RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) }; +		addRecorder(ptr); +		return ptr; +	}  	LL_COMMON_API void logToFile(const std::string& filename);  	LL_COMMON_API void logToStderr(); diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index cf8f8cc6a5..e8ea0ab398 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -59,7 +59,6 @@ public:          // pump name -- so it should NOT need tweaking for uniqueness.          mReplyPump(LLUUID::generateNewID().asString()),          mExpect(0), -        mPrevFatalFunction(LLError::getFatalFunction()),          // 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 @@ -146,7 +145,9 @@ public:              .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));          // For our lifespan, intercept any LL_ERRS so we can notify plugin -        LLError::setFatalFunction(boost::bind(&LLLeapImpl::fatalFunction, this, _1)); +        mRecorder = LLError::addGenericRecorder( +            [this](LLError::ELevel level, const std::string& message) +            { onError(level, message); });          // Send child a preliminary event reporting our own reply-pump name --          // which would otherwise be pretty tricky to guess! @@ -162,8 +163,7 @@ public:      virtual ~LLLeapImpl()      {          LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL; -        // Restore original FatalFunction -        LLError::setFatalFunction(mPrevFatalFunction); +        LLError::removeRecorder(mRecorder);      }      // Listener for failed launch attempt @@ -377,28 +377,28 @@ public:          return false;      } -    void fatalFunction(const std::string& error) +    void onError(LLError::ELevel level, 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) +        if (level == LLError::LEVEL_ERROR)          { -            mainloop.post(nop); +            // 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); +            }          } - -        // forward the call to the previous FatalFunction -        mPrevFatalFunction(error);      }  private: @@ -421,7 +421,7 @@ private:          mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;      boost::scoped_ptr<LLEventPump::Blocker> mBlocker;      LLProcess::ReadPipe::size_type mExpect; -    LLError::FatalFunction mPrevFatalFunction; +    LLError::RecorderPtr mRecorder;      boost::scoped_ptr<LLLeapListener> mListener;  }; diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index ad933154c2..6b1986d0e9 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -38,11 +38,6 @@  #include <sstream>  #include <stdexcept> -namespace { -void log(LLError::ELevel level, -         const char* p1, const char* p2, const char* p3, const char* p4); -} // anonymous namespace -  // Our master list of all LLSingletons is itself an LLSingleton. We used to  // store it in a function-local static, but that could get destroyed before  // the last of the LLSingletons -- and ~LLSingletonBase() definitely wants to @@ -218,8 +213,8 @@ void LLSingletonBase::pop_initializing()      if (list.empty())      { -        logerrs("Underflow in stack of currently-initializing LLSingletons at ", -                classname(this).c_str(), "::getInstance()"); +        logerrs({"Underflow in stack of currently-initializing LLSingletons at ", +                classname(this), "::getInstance()"});      }      // Now we know list.back() exists: capture it @@ -240,9 +235,9 @@ void LLSingletonBase::pop_initializing()      // Now validate the newly-popped LLSingleton.      if (back != this)      { -        logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ", -                classname(this).c_str(), "::getInstance() trying to pop ", -                classname(back).c_str()); +        logerrs({"Push/pop mismatch in stack of currently-initializing LLSingletons: ", +                classname(this), "::getInstance() trying to pop ", +                classname(back)});      }      // log AFTER popping so logging singletons don't cry circularity @@ -331,15 +326,15 @@ void LLSingletonBase::capture_dependency()                  //                  // Example: LLNotifications singleton initializes default channels.                  // Channels register themselves with singleton once done. -                logdebugs("LLSingleton circularity: ", out.str().c_str(), -                    classname(this).c_str(), ""); +                logdebugs({"LLSingleton circularity: ", out.str(), +                          classname(this)});              }              else              {                  // Actual circularity with other singleton (or single singleton is used extensively).                  // Dependency can be unclear. -                logwarns("LLSingleton circularity: ", out.str().c_str(), -                    classname(this).c_str(), ""); +                logwarns({"LLSingleton circularity: ", out.str(), +                         classname(this)});              }          }          else @@ -352,8 +347,8 @@ void LLSingletonBase::capture_dependency()              if (current->mDepends.insert(this).second)              {                  // only log the FIRST time we hit this dependency! -                logdebugs(classname(current).c_str(), -                          " depends on ", classname(this).c_str()); +                logdebugs({classname(current), +                          " depends on ", classname(this)});              }          }      } @@ -401,7 +396,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort()  void LLSingletonBase::cleanup_()  { -    logdebugs("calling ", classname(this).c_str(), "::cleanupSingleton()"); +    logdebugs({"calling ", classname(this), "::cleanupSingleton()"});      try      {          cleanupSingleton(); @@ -427,23 +422,23 @@ void LLSingletonBase::deleteAll()              if (! sp->mDeleteSingleton)              {                  // This Should Not Happen... but carry on. -                logwarns(name.c_str(), "::mDeleteSingleton not initialized!"); +                logwarns({name, "::mDeleteSingleton not initialized!"});              }              else              {                  // properly initialized: call it. -                logdebugs("calling ", name.c_str(), "::deleteSingleton()"); +                logdebugs({"calling ", name, "::deleteSingleton()"});                  // From this point on, DO NOT DEREFERENCE sp!                  sp->mDeleteSingleton();              }          }          catch (const std::exception& e)          { -            logwarns("Exception in ", name.c_str(), "::deleteSingleton(): ", e.what()); +            logwarns({"Exception in ", name, "::deleteSingleton(): ", e.what()});          }          catch (...)          { -            logwarns("Unknown exception in ", name.c_str(), "::deleteSingleton()"); +            logwarns({"Unknown exception in ", name, "::deleteSingleton()"});          }      }  } @@ -451,49 +446,40 @@ void LLSingletonBase::deleteAll()  /*---------------------------- Logging helpers -----------------------------*/  namespace { -void log(LLError::ELevel level, -         const char* p1, const char* p2, const char* p3, const char* p4) +std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params& args)  { -    LL_VLOGS(level, "LLSingleton") << p1 << p2 << p3 << p4 << LL_ENDL; +    // However many args there are in args, stream each of them to 'out'. +    for (auto arg : args) +    { +        out << arg; +    } +    return out;  }  } // anonymous namespace          //static -void LLSingletonBase::logwarns(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::logwarns(const string_params& args)  { -    log(LLError::LEVEL_WARN, p1, p2, p3, p4); +    LL_WARNS("LLSingleton") << args << LL_ENDL;  }  //static -void LLSingletonBase::loginfos(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::loginfos(const string_params& args)  { -    log(LLError::LEVEL_INFO, p1, p2, p3, p4); +    LL_INFOS("LLSingleton") << args << LL_ENDL;  }  //static -void LLSingletonBase::logdebugs(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::logdebugs(const string_params& args)  { -    log(LLError::LEVEL_DEBUG, p1, p2, p3, p4); +    LL_DEBUGS("LLSingleton") << args << LL_ENDL;  }  //static -void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, const char* p4) +void LLSingletonBase::logerrs(const string_params& args)  { -    log(LLError::LEVEL_ERROR, p1, p2, p3, p4); -    // The other important side effect of LL_ERRS() is -    // https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG) -    std::ostringstream out; -    out << p1 << p2 << p3 << p4; -    auto crash = LLError::getFatalFunction(); -    if (crash) -    { -        crash(out.str()); -    } -    else -    { -        LLError::crashAndLoop(out.str()); -    } +    LL_ERRS("LLSingleton") << args << LL_ENDL;  }  std::string LLSingletonBase::demangle(const char* mangled) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 30a5b21cf8..7c81d65a8b 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -27,9 +27,10 @@  #include <boost/noncopyable.hpp>  #include <boost/unordered_set.hpp> +#include <initializer_list>  #include <list> -#include <vector>  #include <typeinfo> +#include <vector>  #include "mutex.h"  #include "lockstatic.h"  #include "llthread.h"               // on_main_thread() @@ -111,14 +112,13 @@ protected:      void capture_dependency();      // delegate logging calls to llsingleton.cpp -    static void logerrs(const char* p1, const char* p2="", -                        const char* p3="", const char* p4=""); -    static void logwarns(const char* p1, const char* p2="", -                         const char* p3="", const char* p4=""); -    static void loginfos(const char* p1, const char* p2="", -                         const char* p3="", const char* p4=""); -    static void logdebugs(const char* p1, const char* p2="", -                          const char* p3="", const char* p4=""); +public: +    typedef std::initializer_list<const std::string> string_params; +protected: +    static void logerrs  (const string_params&); +    static void logwarns (const string_params&); +    static void loginfos (const string_params&); +    static void logdebugs(const string_params&);      static std::string demangle(const char* mangled);      // these classname() declarations restate template functions declared in      // llerror.h because we avoid #including that here @@ -327,8 +327,8 @@ private:              // init stack to its previous size BEFORE logging so log-machinery              // LLSingletons don't record a dependency on DERIVED_TYPE!              LLSingleton_manage_master<DERIVED_TYPE>().reset_initializing(prev_size); -            logwarns("Error constructing ", classname<DERIVED_TYPE>().c_str(), -                     ": ", err.what()); +            logwarns({"Error constructing ", classname<DERIVED_TYPE>(), +                     ": ", err.what()});              // There isn't a separate EInitState value meaning "we attempted              // to construct this LLSingleton subclass but could not," so use              // DELETED. That seems slightly more appropriate than UNINITIALIZED. @@ -356,8 +356,8 @@ private:              // BEFORE logging, so log-machinery LLSingletons don't record a              // dependency on DERIVED_TYPE!              pop_initializing(lk->mInstance); -            logwarns("Error in ", classname<DERIVED_TYPE>().c_str(), -                     "::initSingleton(): ", err.what()); +            logwarns({"Error in ", classname<DERIVED_TYPE>(), +                     "::initSingleton(): ", err.what()});              // Get rid of the instance entirely. This call depends on our              // recursive_mutex. We could have a deleteSingleton(LockStatic&)              // overload and pass lk, but we don't strictly need it. @@ -506,9 +506,9 @@ public:              case CONSTRUCTING:                  // here if DERIVED_TYPE's constructor (directly or indirectly)                  // calls DERIVED_TYPE::getInstance() -                logerrs("Tried to access singleton ", -                        classname<DERIVED_TYPE>().c_str(), -                        " from singleton constructor!"); +                logerrs({"Tried to access singleton ", +                        classname<DERIVED_TYPE>(), +                        " from singleton constructor!"});                  return nullptr;              case INITIALIZING: @@ -523,9 +523,9 @@ public:              case DELETED:                  // called after deleteSingleton() -                logwarns("Trying to access deleted singleton ", -                         classname<DERIVED_TYPE>().c_str(), -                         " -- creating new instance"); +                logwarns({"Trying to access deleted singleton ", +                         classname<DERIVED_TYPE>(), +                         " -- creating new instance"});                  // fall through              case UNINITIALIZED:              case QUEUED: @@ -552,8 +552,8 @@ public:          } // unlock 'lk'          // Per the comment block above, dispatch to the main thread. -        loginfos(classname<DERIVED_TYPE>().c_str(), -                 "::getInstance() dispatching to main thread"); +        loginfos({classname<DERIVED_TYPE>(), +                 "::getInstance() dispatching to main thread"});          auto instance = LLMainThreadTask::dispatch(              [](){                  // VERY IMPORTANT to call getInstance() on the main thread, @@ -563,16 +563,16 @@ public:                  // the main thread processes them, only the FIRST such request                  // actually constructs the instance -- every subsequent one                  // simply returns the existing instance. -                loginfos(classname<DERIVED_TYPE>().c_str(), -                         "::getInstance() on main thread"); +                loginfos({classname<DERIVED_TYPE>(), +                         "::getInstance() on main thread"});                  return getInstance();              });          // record the dependency chain tracked on THIS thread, not the main          // thread (consider a getInstance() overload with a tag param that          // suppresses dep tracking when dispatched to the main thread)          capture_dependency(instance); -        loginfos(classname<DERIVED_TYPE>().c_str(), -                 "::getInstance() returning on requesting thread"); +        loginfos({classname<DERIVED_TYPE>(), +                 "::getInstance() returning on requesting thread"});          return instance;      } @@ -641,16 +641,16 @@ private:          // For organizational purposes this function shouldn't be called twice          if (lk->mInitState != super::UNINITIALIZED)          { -            super::logerrs("Tried to initialize singleton ", -                           super::template classname<DERIVED_TYPE>().c_str(), -                           " twice!"); +            super::logerrs({"Tried to initialize singleton ", +                           super::template classname<DERIVED_TYPE>(), +                           " twice!"});              return nullptr;          }          else if (on_main_thread())          {              // on the main thread, simply construct instance while holding lock -            super::logdebugs(super::template classname<DERIVED_TYPE>().c_str(), -                             "::initParamSingleton()"); +            super::logdebugs({super::template classname<DERIVED_TYPE>(), +                             "::initParamSingleton()"});              super::constructSingleton(lk, std::forward<Args>(args)...);              return lk->mInstance;          } @@ -662,8 +662,8 @@ private:              lk->mInitState = super::QUEUED;              // very important to unlock here so main thread can actually process              lk.unlock(); -            super::loginfos(super::template classname<DERIVED_TYPE>().c_str(), -                            "::initParamSingleton() dispatching to main thread"); +            super::loginfos({super::template classname<DERIVED_TYPE>(), +                            "::initParamSingleton() dispatching to main thread"});              // Normally it would be the height of folly to reference-bind              // 'args' into a lambda to be executed on some other thread! By              // the time that thread executed the lambda, the references would @@ -674,12 +674,12 @@ private:              // references.              auto instance = LLMainThreadTask::dispatch(                  [&](){ -                    super::loginfos(super::template classname<DERIVED_TYPE>().c_str(), -                                    "::initParamSingleton() on main thread"); +                    super::loginfos({super::template classname<DERIVED_TYPE>(), +                                    "::initParamSingleton() on main thread"});                      return initParamSingleton_(std::forward<Args>(args)...);                  }); -            super::loginfos(super::template classname<DERIVED_TYPE>().c_str(), -                            "::initParamSingleton() returning on requesting thread"); +            super::loginfos({super::template classname<DERIVED_TYPE>(), +                            "::initParamSingleton() returning on requesting thread"});              return instance;          }      } @@ -707,14 +707,14 @@ public:          {          case super::UNINITIALIZED:          case super::QUEUED: -            super::logerrs("Uninitialized param singleton ", -                           super::template classname<DERIVED_TYPE>().c_str()); +            super::logerrs({"Uninitialized param singleton ", +                           super::template classname<DERIVED_TYPE>()});              break;          case super::CONSTRUCTING: -            super::logerrs("Tried to access param singleton ", -                           super::template classname<DERIVED_TYPE>().c_str(), -                           " from singleton constructor!"); +            super::logerrs({"Tried to access param singleton ", +                           super::template classname<DERIVED_TYPE>(), +                           " from singleton constructor!"});              break;          case super::INITIALIZING: @@ -726,8 +726,8 @@ public:              return lk->mInstance;          case super::DELETED: -            super::logerrs("Trying to access deleted param singleton ", -                           super::template classname<DERIVED_TYPE>().c_str()); +            super::logerrs({"Trying to access deleted param singleton ", +                           super::template classname<DERIVED_TYPE>()});              break;          } diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 8e1f4c14ac..148c18aabe 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -26,6 +26,7 @@   */  #include <vector> +#include <stdexcept>  #include "linden_common.h" @@ -69,21 +70,41 @@ namespace  namespace  { -	static bool fatalWasCalled; -	void fatalCall(const std::string&) { fatalWasCalled = true; } +	static bool fatalWasCalled = false; +    struct FatalWasCalled: public std::runtime_error +    { +        FatalWasCalled(const std::string& what): std::runtime_error(what) {} +    }; +    void fatalCall(const std::string& msg) { throw FatalWasCalled(msg); }  } +// Because we use LLError::setFatalFunction(fatalCall), any LL_ERRS call we +// issue will throw FatalWasCalled. But we want the test program to continue. +// So instead of writing: +// LL_ERRS("tag") << "some message" << LL_ENDL; +// write: +// CATCH(LL_ERRS("tag"), "some message"); +#define CATCH(logcall, expr)                    \ +    try                                         \ +    {                                           \ +        logcall << expr << LL_ENDL;             \ +    }                                           \ +    catch (const FatalWasCalled&)               \ +    {                                           \ +        fatalWasCalled = true;                  \ +    } +  namespace tut  {  	class TestRecorder : public LLError::Recorder  	{  	public:  		TestRecorder() -            { -                showTime(false); -            } +			{ +				showTime(false); +			}  		virtual ~TestRecorder() -            {} +			{}  		virtual void recordMessage(LLError::ELevel level,  						   const std::string& message) @@ -252,7 +273,7 @@ namespace  		LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL;  		LL_INFOS("WriteTag") << "two" << LL_ENDL;  		LL_WARNS("WriteTag") << "three" << LL_ENDL; -		LL_ERRS("WriteTag") << "four" << LL_ENDL; +		CATCH(LL_ERRS("WriteTag"), "four");  	}  }; @@ -380,7 +401,7 @@ namespace  	std::string errorReturningLocation()  	{ -		LL_ERRS() << "die" << LL_ENDL;	int this_line = __LINE__; +		int this_line = __LINE__;	CATCH(LL_ERRS(), "die");  		return locationString(this_line);  	}  } @@ -701,7 +722,7 @@ public:  	static void doDebug()	{ LL_DEBUGS() << "add dice" << LL_ENDL; }  	static void doInfo()	{ LL_INFOS()  << "any idea" << LL_ENDL; }  	static void doWarn()	{ LL_WARNS()  << "aim west" << LL_ENDL; } -	static void doError()	{ LL_ERRS()   << "ate eels" << LL_ENDL; } +	static void doError()	{ CATCH(LL_ERRS(), "ate eels"); }  	static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }  }; @@ -712,7 +733,7 @@ public:  	static void doDebug()	{ LL_DEBUGS() << "bed down" << LL_ENDL; }  	static void doInfo()	{ LL_INFOS()  << "buy iron" << LL_ENDL; }  	static void doWarn()	{ LL_WARNS()  << "bad word" << LL_ENDL; } -	static void doError()	{ LL_ERRS()   << "big easy" << LL_ENDL; } +	static void doError()	{ CATCH(LL_ERRS(), "big easy"); }  	static void doAll() { doDebug(); doInfo(); doWarn(); doError(); }  }; @@ -874,13 +895,10 @@ namespace tut  namespace  {      std::string writeTagWithSpaceReturningLocation() -	{ -        LL_DEBUGS("Write Tag") << "not allowed" << LL_ENDL;	int this_line = __LINE__; -         -        std::ostringstream location; -        location << LLError::abbreviateFile(__FILE__).c_str() << "(" << this_line << ")"; -        return location.str(); -	} +    { +        int this_line = __LINE__; CATCH(LL_DEBUGS("Write Tag"), "not allowed"); +        return locationString(this_line); +    }  };  namespace tut @@ -894,9 +912,9 @@ namespace tut          std::string location = writeTagWithSpaceReturningLocation();          std::string expected = "Space is not allowed in a log tag at " + location; -		ensure_message_field_equals(0, LEVEL_FIELD, "ERROR"); -		ensure_message_field_equals(0, MSG_FIELD, expected); -		ensure("fatal callback called", fatalWasCalled); +        ensure_message_field_equals(0, LEVEL_FIELD, "ERROR"); +        ensure_message_field_equals(0, MSG_FIELD, expected); +        ensure("fatal callback called", fatalWasCalled);      }  } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index b07d5afbd8..3779fb41bc 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -44,10 +44,6 @@  #include <list>  #include <string> -// statically reference the function in test.cpp... it's short, we could -// replicate, but better to reuse -extern void wouldHaveCrashed(const std::string& message); -  struct WrapLLErrs  {      WrapLLErrs(): @@ -59,7 +55,8 @@ struct WrapLLErrs          mPriorFatal(LLError::getFatalFunction())      {          // Make LL_ERRS call our own operator() method -        LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1)); +        LLError::setFatalFunction( +            [this](const std::string& message){ (*this)(message); });      }      ~WrapLLErrs() @@ -199,11 +196,13 @@ public:          // with that output. If it turns out that saveAndResetSettings() has          // some bad effect, give up and just let the DEBUG level log messages          // display. -		: boost::noncopyable(), +        : boost::noncopyable(), +        mFatalFunction(LLError::getFatalFunction()),          mOldSettings(LLError::saveAndResetSettings()), -		mRecorder(new CaptureLogRecorder()) +        mRecorder(new CaptureLogRecorder())      { -        LLError::setFatalFunction(wouldHaveCrashed); +        // reinstate the FatalFunction we just reset +        LLError::setFatalFunction(mFatalFunction);          LLError::setDefaultLevel(level);          LLError::addRecorder(mRecorder);      } @@ -219,17 +218,18 @@ public:      /// for the sought string.      std::string messageWith(const std::string& search, bool required=true)      { -		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required); +        return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required);      }      std::ostream& streamto(std::ostream& out) const      { -		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out); +        return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out);      }  private: +    LLError::FatalFunction mFatalFunction;      LLError::SettingsStoragePtr mOldSettings; -	LLError::RecorderPtr mRecorder; +    LLError::RecorderPtr mRecorder;  };  #endif /* ! defined(LL_WRAPLLERRS_H) */ diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 240ea2da83..8bb6a657b1 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/llcrashlogger/README.txt b/indra/llcrashlogger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/llcrashlogger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt index 293ada7548..28b8e8c06d 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 999bee0a3f..552e820127 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/mac_crash_logger/README.txt b/indra/mac_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/mac_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5ea2d0f7a5..62e73b78da 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) @@ -96,18 +94,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 @@ -1414,11 +1412,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 @@ -1756,10 +1754,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) +    PROPERTY COMPILE_DEFINITIONS "${BUGSPLAT_DEFINE}") +endif (USE_BUGSPLAT)  # add package files  file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST @@ -1838,9 +1836,12 @@ if (WINDOWS)        media_plugin_libvlc        media_plugin_example        winmm_shim -      windows-crash-logger        ) +    if (NOT USE_BUGSPLAT) +        LIST(APPEND COPY_INPUT_DEPENDENCIES windows-crash-logger) +    endif (NOT USE_BUGSPLAT) +      if (ADDRESS_SIZE EQUAL 64)          list(APPEND COPY_INPUT_DEPENDENCIES              ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/vivoxsdk_x64.dll @@ -1903,10 +1904,11 @@ if (WINDOWS)        add_dependencies(${VIEWER_BINARY_NAME} copy_win_scripts)      endif (EXISTS ${CMAKE_SOURCE_DIR}/copy_win_scripts) -    add_dependencies(${VIEWER_BINARY_NAME} -      SLPlugin -      windows-crash-logger -    ) +    add_dependencies(${VIEWER_BINARY_NAME} SLPlugin) + +    if (NOT USE_BUGSPLAT) +        add_dependencies(${VIEWER_BINARY_NAME} windows-crash-logger) +    endif (NOT USE_BUGSPLAT)      # sets the 'working directory' for debugging from visual studio.      # Condition for version can be moved to requirements once build agents will be updated (see TOOL-3865) @@ -2058,11 +2060,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.") @@ -2073,13 +2075,16 @@ if (LINUX)    # These are the generated targets that are copied to package/    set(COPY_INPUT_DEPENDENCIES      ${VIEWER_BINARY_NAME} -    linux-crash-logger      SLPlugin      media_plugin_gstreamer010      media_plugin_libvlc      llcommon      ) +  if (NOT USE_BUGSPLAT) +      LIST(APPEND COPY_INPUT_DEPENDENCIES linux-crash-logger) +  endif (NOT USE_BUGSPLAT) +    add_custom_command(        OUTPUT ${product}.tar.bz2        COMMAND ${PYTHON_EXECUTABLE} @@ -2210,8 +2215,11 @@ if (DARWIN)        ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py      ) -  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef mac-crash-logger) -  add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger) +  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_libvlc media_plugin_cef) + +  if (NOT USE_BUGSPLAT) +      add_dependencies(${VIEWER_BINARY_NAME} mac-crash-logger) +  endif (NOT USE_BUGSPLAT)    if (ENABLE_SIGNING)        set(SIGNING_SETTING "--signature=${SIGNING_IDENTITY}") @@ -2254,7 +2262,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) @@ -2271,7 +2279,7 @@ if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND VIE        list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/llplugin/slplugin/${CMAKE_CFG_INTDIR}")        list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}")        list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") -      set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger") +      set(VIEWER_EXE_GLOBS "'${product}' SLPlugin")        set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger")        set(VIEWER_LIB_GLOB "*.dylib")      endif (DARWIN) @@ -2309,7 +2317,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 @@ -2393,9 +2401,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/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index 3f1b5139c5..aeb3294f53 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -66,6 +66,7 @@  	constructViewer();  #if defined(LL_BUGSPLAT) +    infos("bugsplat setup");  	// Engage BugsplatStartupManager *before* calling initViewer() to handle  	// any crashes during initialization.  	// https://www.bugsplat.com/docs/platforms/os-x#initialization @@ -74,6 +75,7 @@  	[BugsplatStartupManager sharedManager].delegate = self;  	[[BugsplatStartupManager sharedManager] start];  #endif +    infos("post-bugsplat setup");  	frameTimer = nil; @@ -301,9 +303,13 @@ struct AttachmentInfo      // We "happen to know" that info[0].basename is "SecondLife.old" -- due to      // the fact that BugsplatMac only notices a crash during the viewer run -    // following the crash. Replace .old with .log to reduce confusion. +    // following the crash.  +    // The Bugsplat service doesn't respect the MIME type above when returning +    // the log data to a browser, so take this opportunity to rename the file +    // from <base>.old to <base>_log.txt      info[0].basename =  -        boost::filesystem::path(info[0].pathname).stem().string() + ".log"; +        boost::filesystem::path(info[0].pathname).stem().string() + "_log.txt"; +    infos("attachmentsForBugsplatStartupManager attaching log " + info[0].basename);      NSMutableArray *attachments = [[NSMutableArray alloc] init]; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a13ba97987..959587dd11 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -728,14 +728,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); @@ -760,17 +760,6 @@ public:  	}  }; -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()  { @@ -822,9 +811,9 @@ bool LLAppViewer::init()  	if (rc >= 0)  	{  		// QAModeTermCode set, terminate with that rc on LL_ERRS. Use -		// fast_exit() rather than exit() because normal cleanup depends too +		// _exit() rather than exit() because normal cleanup depends too  		// much on successful startup! -		LLError::setFatalFunction(boost::bind(fast_exit, rc)); +		LLError::setFatalFunction([rc](const std::string&){ _exit(rc); });  	}      mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); @@ -2185,28 +2174,6 @@ bool LLAppViewer::cleanup()  	return true;  } -// A callback for LL_ERRS() to call during the watchdog error. -void watchdog_llerrs_callback(const std::string &error_string) -{ -	gLLErrorActivated = true; - -	gDebugInfo["FatalMessage"] = error_string; -	LLAppViewer::instance()->writeDebugInfo(); - -#ifdef LL_WINDOWS -	RaiseException(0,0,0,0); -#else -	raise(SIGQUIT); -#endif -} - -// A callback for the watchdog to call. -void watchdog_killer_callback() -{ -	LLError::setFatalFunction(watchdog_llerrs_callback); -	LL_ERRS() << "Watchdog killer event" << LL_ENDL; -} -  bool LLAppViewer::initThreads()  {  	static const bool enable_threads = true; @@ -2241,24 +2208,23 @@ bool LLAppViewer::initThreads()  	return true;  } -void errorCallback(const std::string &error_string) +void errorCallback(LLError::ELevel level, const std::string &error_string)  { +    if (level == LLError::LEVEL_ERROR) +    {  #ifndef LL_RELEASE_FOR_DOWNLOAD -	OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK); +        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(); +        //Set the ErrorActivated global so we know to create a marker file +        gLLErrorActivated = true; -#ifndef SHADER_CRASH_NONFATAL -	LLError::crashAndLoop(error_string); -#endif +        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(); +    }  }  void LLAppViewer::initLoggingAndGetLastDuration() @@ -2269,7 +2235,7 @@ void LLAppViewer::initLoggingAndGetLastDuration()  	LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "")                                  ,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")                                  ); -	LLError::setFatalFunction(errorCallback); +	LLError::addGenericRecorder(&errorCallback);  	//LLError::setTimeFunction(getRuntime);  	// Remove the last ".old" log file. @@ -3028,11 +2994,16 @@ bool LLAppViewer::initWindow()  		use_watchdog = bool(watchdog_enabled_setting);  	} +	LL_INFOS("AppInit") << "watchdog" +						<< (use_watchdog ? " " : " NOT ") +						<< "enabled" +						<< " (setting = " << watchdog_enabled_setting << ")" +						<< LL_ENDL; +  	if (use_watchdog)  	{ -		LLWatchdog::getInstance()->init(watchdog_killer_callback); +		LLWatchdog::getInstance()->init();  	} -	LL_INFOS("AppInit") << "watchdog setting is done." << LL_ENDL;  	LLNotificationsUI::LLNotificationManager::getInstance(); @@ -3465,8 +3436,8 @@ void LLAppViewer::writeSystemInfo()  	gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();  	gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2(); -	gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB().value()); -	gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>()); +	gDebugInfo["RAMInfo"]["Physical"] = LLSD::Integer(gSysMemory.getPhysicalMemoryKB().value()); +	gDebugInfo["RAMInfo"]["Allocated"] = LLSD::Integer(gMemoryAllocated.valueInUnits<LLUnits::Kilobytes>());  	gDebugInfo["OSInfo"] = LLOSInfo::instance().getOSStringSimple();  	// The user is not logged on yet, but record the current grid choice login url @@ -3479,12 +3450,18 @@ 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; +	gDebugInfo["CrashNotHandled"] = LLSD::Boolean(true); +#else // LL_BUGSPLAT +	// "CrashNotHandled" is obsolete; it used (not very successsfully) +    // to try to distinguish crashes from freezes - the intent here to to avoid calling it a freeze +	gDebugInfo["CrashNotHandled"] = LLSD::Boolean(false); +#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 @@ -3515,7 +3492,7 @@ void LLAppViewer::writeSystemInfo()      gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");  	gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();  	gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); -	gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); +	gDebugInfo["FirstLogin"] = LLSD::Boolean(gAgent.isFirstLogin());  	gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");      gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); @@ -3645,7 +3622,7 @@ void LLAppViewer::handleViewerCrash()  	// The crash is being handled here so set this value to false.  	// Otherwise the crash logger will think this crash was a freeze. -	gDebugInfo["Dynamic"]["CrashNotHandled"] = (LLSD::Boolean)false; +	gDebugInfo["Dynamic"]["CrashNotHandled"] = LLSD::Boolean(false);  	//Write out the crash status file  	//Use marker file style setup, as that's the simplest, especially since @@ -3718,6 +3695,8 @@ void LLAppViewer::handleViewerCrash()  	if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo["Dynamic"]); +	gDebugInfo["FatalMessage"] = LLError::getFatalMessage(); +  	// Close the debug file  	pApp->writeDebugInfo(false);  //false answers the isStatic question with the least overhead.  } @@ -3816,9 +3795,8 @@ void LLAppViewer::processMarkerFiles()  		else if (marker_is_same_version)  		{  			// the file existed, is ours, and matched our version, so we can report on what it says -			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL; -			gLastExecEvent = LAST_EXEC_FROZE; - +			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec crashed" << LL_ENDL; +			gLastExecEvent = LAST_EXEC_OTHER_CRASH;  		}  		else  		{ @@ -5754,11 +5732,6 @@ void LLAppViewer::pauseMainloopTimeout()  void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)  { -//	if(!restoreErrorTrap()) -//	{ -//		LL_WARNS() << "!!!!!!!!!!!!! Its an error trap!!!!" << state << LL_ENDL; -//	} -  	if(mMainloopTimeout)  	{  		if(secs < 0.0f) diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 662164af2d..42946e4415 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -68,39 +68,21 @@ namespace  	int gArgC;  	char** gArgV;  	LLAppViewerMacOSX* gViewerAppPtr = NULL; - -    void (*gOldTerminateHandler)() = NULL;      std::string gHandleSLURL;  } -static void exceptionTerminateHandler() -{ -	// reinstall default terminate() handler in case we re-terminate. -	if (gOldTerminateHandler) std::set_terminate(gOldTerminateHandler); -	// treat this like a regular viewer crash, with nice stacktrace etc. -    long *null_ptr; -    null_ptr = 0; -    *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. -	//LLAppViewer::handleViewerCrash(); -	// we've probably been killed-off before now, but... -	gOldTerminateHandler(); // call old terminate() handler -} -  void constructViewer()  {  	// Set the working dir to <bundle>/Contents/Resources  	if (chdir(gDirUtilp->getAppRODataDir().c_str()) == -1)  	{ -		LL_WARNS() << "Could not change directory to " +		LL_WARNS("InitOSX") << "Could not change directory to "  				<< gDirUtilp->getAppRODataDir() << ": " << strerror(errno)  				<< LL_ENDL;  	}  	gViewerAppPtr = new LLAppViewerMacOSX(); -    // install unexpected exception handler -	gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler); -  	gViewerAppPtr->setErrorHandler(LLAppViewer::handleViewerCrash);  } @@ -109,7 +91,7 @@ bool initViewer()  	bool ok = gViewerAppPtr->init();  	if(!ok)  	{ -		LL_WARNS() << "Application init failed." << LL_ENDL; +		LL_WARNS("InitOSX") << "Application init failed." << LL_ENDL;  	}  	else if (!gHandleSLURL.empty())  	{ @@ -172,7 +154,7 @@ class CrashMetadataSingleton: public CrashMetadata, public LLSingleton<CrashMeta      std::string get_metadata(const LLSD& info, const LLSD::String& key) const      {          std::string data(info[key].asString()); -        LL_INFOS() << "  " << key << "='" << data << "'" << LL_ENDL; +        LL_INFOS("Bugsplat") << "  " << key << "='" << data << "'" << LL_ENDL;          return data;      }  }; @@ -188,22 +170,22 @@ CrashMetadataSingleton::CrashMetadataSingleton()      LLSD info;      if (! static_file.is_open())      { -        LL_INFOS() << "Can't open '" << staticDebugPathname +        LL_WARNS("Bugsplat") << "Can't open '" << staticDebugPathname                     << "'; no metadata about previous run" << LL_ENDL;      }      else if (! LLSDSerialize::deserialize(info, static_file, LLSDSerialize::SIZE_UNLIMITED))      { -        LL_INFOS() << "Can't parse '" << staticDebugPathname +        LL_WARNS("Bugsplat") << "Can't parse '" << staticDebugPathname                     << "'; no metadata about previous run" << LL_ENDL;      }      else      { -        LL_INFOS() << "Metadata from '" << staticDebugPathname << "':" << LL_ENDL; -        logFilePathname         = get_metadata(info, "SLLog"); -        userSettingsPathname    = get_metadata(info, "SettingsFilename"); +        LL_INFOS("Bugsplat") << "Previous run metadata from '" << staticDebugPathname << "':" << LL_ENDL; +        logFilePathname      = get_metadata(info, "SLLog"); +        userSettingsPathname = get_metadata(info, "SettingsFilename");          accountSettingsPathname = get_metadata(info, "PerAccountSettingsFilename"); -        OSInfo                  = get_metadata(info, "OSInfo"); -        agentFullname           = get_metadata(info, "LoginName"); +        OSInfo               = get_metadata(info, "OSInfo"); +        agentFullname        = get_metadata(info, "LoginName");          // Translate underscores back to spaces          LLStringUtil::replaceChar(agentFullname, '_', ' ');          regionName           = get_metadata(info, "CurrentRegion"); @@ -219,7 +201,7 @@ CrashMetadata& CrashMetadata_instance()  void infos(const std::string& message)  { -    LL_INFOS() << message << LL_ENDL; +    LL_INFOS("InitOSX", "Bugsplat") << message << LL_ENDL;  }  int main( int argc, char **argv )  @@ -242,14 +224,11 @@ bool LLAppViewerMacOSX::init()  {  	bool success = LLAppViewer::init(); -#if LL_SEND_CRASH_REPORTS      if (success)      {          LLAppViewer* pApp = LLAppViewer::instance();          pApp->initCrashReporting();      } -#endif -          return success;  } @@ -334,11 +313,12 @@ bool LLAppViewerMacOSX::restoreErrorTrap()  	unsigned int reset_count = 0; -#define SET_SIG(S) 	sigaction(SIGABRT, &act, &old_act); \ -					if(act.sa_sigaction != old_act.sa_sigaction) \ -						++reset_count; +#define SET_SIG(SIGNAL) sigaction(SIGNAL, &act, &old_act); \ +                        if(act.sa_sigaction != old_act.sa_sigaction) ++reset_count;  	// Synchronous signals -	SET_SIG(SIGABRT) +#   ifndef LL_BUGSPLAT +	SET_SIG(SIGABRT) // let bugsplat catch this +#   endif          	SET_SIG(SIGALRM)  	SET_SIG(SIGBUS)  	SET_SIG(SIGFPE) @@ -369,6 +349,10 @@ bool LLAppViewerMacOSX::restoreErrorTrap()  void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)  { +#if defined LL_BUGSPLAT +    LL_DEBUGS("InitOSX", "Bugsplat") << "using BugSplat crash logger" << LL_ENDL; +#elif LL_SEND_CRASH_REPORTS +    LL_DEBUGS("InitOSX") << "Initializing legacy crash logger" << LL_ENDL;  	std::string command_str = "mac-crash-logger.app";      std::stringstream pid_str; @@ -380,6 +364,9 @@ void LLAppViewerMacOSX::initCrashReporting(bool reportFreeze)      LL_WARNS() << "about to launch mac-crash-logger" << pid_str.str()                 << " " << logdir << " " << appname << LL_ENDL;      launchApplication(&command_str, &args); +#else +    LL_DEBUGS("InitOSX") << "No crash logger enabled" << LL_ENDL;     +#endif // ! LL_BUGSPLAT  }  std::string LLAppViewerMacOSX::generateSerialNumber() @@ -391,7 +378,8 @@ std::string LLAppViewerMacOSX::generateSerialNumber()  	CFStringRef serialNumber = NULL;  	io_service_t    platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,  																 IOServiceMatching("IOPlatformExpertDevice")); -	if (platformExpert) { +	if (platformExpert) +    {  		serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert,  																	 CFSTR(kIOPlatformSerialNumberKey),  																	 kCFAllocatorDefault, 0);		 diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index ce36d3458e..9daea515e5 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -177,7 +177,7 @@ static void exceptionTerminateHandler()      long *null_ptr;      null_ptr = 0;      *null_ptr = 0xDEADBEEF; //Force an exception that will trigger breakpad. -	//LLAppViewer::handleViewerCrash(); +  	// we've probably been killed-off before now, but...  	gOldTerminateHandler(); // call old terminate() handler  } @@ -365,10 +365,6 @@ int APIENTRY WINMAIN(HINSTANCE hInstance,  	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash); -#if LL_SEND_CRASH_REPORTS  -	// ::SetUnhandledExceptionFilter(catchallCrashHandler);  -#endif -  	// Set a debug info flag to indicate if multiple instances are running.  	bool found_other_instance = !create_app_mutex();  	gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance); @@ -847,8 +843,7 @@ bool LLAppViewerWin32::beingDebugged()  bool LLAppViewerWin32::restoreErrorTrap()  {	 -	return true; -	//return LLWinDebug::checkExceptionHandler(); +	return true; // we don't check for handler collisions on windows, so just say they're ok  }  void LLAppViewerWin32::initCrashReporting(bool reportFreeze) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 43e77e0b08..0416ec0883 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1812,7 +1812,8 @@ LLViewerWindow::LLViewerWindow(const Params& p)  	if (!LLAppViewer::instance()->restoreErrorTrap())  	{ -		LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL; +        // this always happens, so downgrading it to INFO +		LL_INFOS("Window") << " Someone took over my signal/exception handler (post createWindow; normal)" << LL_ENDL;  	}  	const bool do_not_enforce = false; diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 6273f10c69..0aa0280b25 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -31,15 +31,6 @@  const U32 WATCHDOG_SLEEP_TIME_USEC = 1000000; -void default_killer_callback() -{ -#ifdef LL_WINDOWS -	RaiseException(0,0,0,0); -#else -	raise(SIGQUIT); -#endif -} -  // This class runs the watchdog timing thread.  class LLWatchdogTimerThread : public LLThread  { @@ -158,11 +149,10 @@ void LLWatchdogTimeout::ping(const std::string& state)  }  // LLWatchdog -LLWatchdog::LLWatchdog() : -	mSuspectsAccessMutex(), -	mTimer(NULL), -	mLastClockCount(0), -	mKillerCallback(&default_killer_callback) +LLWatchdog::LLWatchdog() +    :mSuspectsAccessMutex() +    ,mTimer(NULL) +	,mLastClockCount(0)  {  } @@ -184,9 +174,8 @@ void LLWatchdog::remove(LLWatchdogEntry* e)  	unlockThread();  } -void LLWatchdog::init(killer_event_callback func) +void LLWatchdog::init()  { -	mKillerCallback = func;  	if(!mSuspectsAccessMutex && !mTimer)  	{  		mSuspectsAccessMutex = new LLMutex(); @@ -253,8 +242,7 @@ void LLWatchdog::run()  				mTimer->stop();  			} -			LL_INFOS() << "Watchdog detected error:" << LL_ENDL; -			mKillerCallback(); +            LL_ERRS() << "Watchdog timer expired; assuming viewer is hung and crashing" << LL_ENDL;  		}  	} diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h index 9a6624258e..ce5cf748f4 100644 --- a/indra/newview/llwatchdog.h +++ b/indra/newview/llwatchdog.h @@ -83,9 +83,7 @@ public:  	void add(LLWatchdogEntry* e);  	void remove(LLWatchdogEntry* e); -	typedef boost::function<void (void)> killer_event_callback; - -	void init(killer_event_callback func = NULL); +	void init();  	void run();  	void cleanup(); @@ -98,8 +96,6 @@ private:  	LLMutex* mSuspectsAccessMutex;  	LLWatchdogTimerThread* mTimer;  	U64 mLastClockCount; - -	killer_event_callback mKillerCallback;  };  #endif // LL_LLTHREADWATCHDOG_H diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index adac7af712..9f9821b4be 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -683,10 +683,11 @@ class WindowsManifest(ViewerManifest):                  self.path("libvlccore.dll")                  self.path("plugins/") -        # pull in the crash logger from other projects -        # tag:"crash-logger" here as a cue to the exporter -        self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], -                  dst="win_crash_logger.exe") +        if not self.args.get('bugsplat'): # don't include the win_crash_logger if we are using BugSplat +            # pull in the crash logger from other projects +            # tag:"crash-logger" here as a cue to the exporter +            self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'], +                      dst="win_crash_logger.exe")          if not self.is_packaging_viewer():              self.package_file = "copied_deps"     @@ -1068,10 +1069,8 @@ class DarwinManifest(ViewerManifest):                  # our apps                  executable_path = {} -                for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), -                                         # plugin launcher -                                         (os.path.join("llplugin", "slplugin"), "SLPlugin.app"), -                                         ): +                embedded_apps = [ (os.path.join("llplugin", "slplugin"), "SLPlugin.app") ] +                for app_bld_dir, app in embedded_apps:                      self.path2basename(os.path.join(os.pardir,                                                      app_bld_dir, self.args['configuration']),                                         app) diff --git a/indra/test/CMakeLists.txt b/indra/test/CMakeLists.txt index 87536e146b..251100867f 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( @@ -83,6 +83,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      ${LEGACY_STDIO_LIBS}      ${LLDATABASE_LIBRARIES} diff --git a/indra/win_crash_logger/README.txt b/indra/win_crash_logger/README.txt new file mode 100644 index 0000000000..6932a8d9c3 --- /dev/null +++ b/indra/win_crash_logger/README.txt @@ -0,0 +1,3 @@ +This component is no longer used in Linden Lab builds. +Change requests to support continued use by open source +builds are welcome. | 
