diff options
34 files changed, 359 insertions, 367 deletions
| diff --git a/BuildParams b/BuildParams index c5f96d5ee3..c5f96d5ee3 100755..100644 --- a/BuildParams +++ b/BuildParams @@ -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 @@ -429,6 +424,15 @@ then    fi  fi +# Some of the uploads takes a long time to finish in the codeticket backend, +# causing the next codeticket upload attempt to fail. +# Inserting this after each potentially large upload may prevent those errors. +# JJ is making changes to Codeticket that we hope will eliminate this failure, then this can be removed +wait_for_codeticket() +{ +    sleep $(( 60 * 6 )) +} +  # check status and upload results to S3  if $succeeded  then @@ -445,6 +449,7 @@ then        # Upload base package.        python_cmd "$helpers/codeticket.py" addoutput Installer "$package"  \            || fatal "Upload of installer failed" +      wait_for_codeticket        # Upload additional packages.        for package_id in $additional_packages @@ -454,6 +459,7 @@ then          then            python_cmd "$helpers/codeticket.py" addoutput "Installer $package_id" "$package" \                || fatal "Upload of installer $package_id failed" +          wait_for_codeticket          else            record_failure "Failed to find additional package for '$package_id'."          fi @@ -467,6 +473,7 @@ then                # Upload crash reporter file                python_cmd "$helpers/codeticket.py" addoutput "Symbolfile" "$VIEWER_SYMBOL_FILE" \                    || fatal "Upload of symbolfile failed" +              wait_for_codeticket            fi            # Upload the llphysicsextensions_tpv package, if one was produced @@ -474,6 +481,9 @@ then            if [ -r "$build_dir/llphysicsextensions_package" ]            then                llphysicsextensions_package=$(cat $build_dir/llphysicsextensions_package) +              # This next upload is a frequent failure; see if giving the last one some time helps +              # JJ is making changes to Codeticket that we hope will eliminate this failure soon +              sleep 300                python_cmd "$helpers/codeticket.py" addoutput "Physics Extensions Package" "$llphysicsextensions_package" --private \                    || fatal "Upload of physics extensions package failed"            fi @@ -484,6 +494,7 @@ then            for extension in ${build_dir}/packages/upload-extensions/*.sh; do                begin_section "Upload Extension $extension"                . $extension +              wait_for_codeticket                end_section "Upload Extension $extension"            done        fi @@ -493,7 +504,6 @@ then      record_event "skipping upload of installer"    fi -    else      record_event "skipping upload of installer due to failed build"  fi 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 429bda473b..ec27267d9d 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -65,7 +65,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) @@ -75,7 +75,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 eeb315ead6..79aa18eaec 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) @@ -258,10 +259,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 3dab632aef..252d08c830 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 411412c883..922c003443 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" @@ -499,7 +500,7 @@ namespace LLError  		LevelMap                            mTagLevelMap;  		std::map<std::string, unsigned int> mUniqueLogMessages; -		LLError::FatalFunction              mCrashFunction; +		LLError::FatalHook                  mFatalHook;  		LLError::TimeFunction               mTimeFunction;  		Recorders                           mRecorders; @@ -536,7 +537,7 @@ namespace LLError  		mFileLevelMap(),  		mTagLevelMap(),  		mUniqueLogMessages(), -		mCrashFunction(NULL), +		mFatalHook(NULL),  		mTimeFunction(NULL),  		mRecorders(),  		mShouldLogCallCounter(0) @@ -708,9 +709,9 @@ namespace  		LLError::Settings::getInstance()->reset();  		LLError::setDefaultLevel(LLError::LEVEL_INFO); -		LLError::setAlwaysFlush(true); -		LLError::setEnabledLogTypesMask(0xFFFFFFFF); -		LLError::setFatalFunction(LLError::crashAndLoop); + +        LLError::setAlwaysFlush(true); +        LLError::setEnabledLogTypesMask(0xFFFFFFFF);  		LLError::setTimeFunction(LLError::utcTime);  		// log_to_stderr is only false in the unit and integration tests to keep builds quieter @@ -745,16 +746,20 @@ namespace LLError  		commonInit(user_dir, app_dir, log_to_stderr);  	} -	void setFatalFunction(const FatalFunction& f) +	void setFatalHook(const FatalHook& fatal_hook)  	{  		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		s->mCrashFunction = f; -	} - -	FatalFunction getFatalFunction() +        LL_DEBUGS("FatalHook") << "set fatal hook to " << (fatal_hook ? "non-null" : "null") +                               << " was " << (s->mFatalHook ? "non-null" : "null") +                               << LL_ENDL; +		s->mFatalHook = fatal_hook; +    } +     +	FatalHook getFatalHook()  	{  		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		return s->mCrashFunction; +        LL_DEBUGS("FatalHook") << "read fatal hook was " << (s->mFatalHook ? "non-null" : "null") << LL_ENDL; +		return s->mFatalHook;  	}  	std::string getFatalMessage() @@ -1410,12 +1415,12 @@ namespace LLError  		return ;  	} -	void Log::flush(std::ostringstream* out, const CallSite& site) +	ErrFatalHookResult Log::flush(std::ostringstream* out, const CallSite& site)  	{  		LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5);  		if (!lock.isLocked())  		{ -			return; +			return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal  		}  		// If we hit a logging request very late during shutdown processing, @@ -1423,7 +1428,7 @@ namespace LLError  		// DO NOT resurrect them.  		if (Settings::wasDeleted() || Globals::wasDeleted())  		{ -			return; +            return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal  		}  		Globals* g = Globals::getInstance(); @@ -1457,7 +1462,7 @@ namespace LLError  				}   				else  				{ -					return; +					return ERR_DO_NOT_CRASH; // because this wasn't logged, it cannot be fatal  				}  			}  			else  @@ -1473,12 +1478,19 @@ namespace LLError  		if (site.mLevel == LEVEL_ERROR)  		{ -			g->mFatalMessage = message; -			if (s->mCrashFunction) -			{ -				s->mCrashFunction(message); -			} +            if (s->mFatalHook) +            { +                return s->mFatalHook(message); +            } +            else +            { +                return ERR_CRASH; // calling macro should crash +            }  		} +        else +        { +            return ERR_DO_NOT_CRASH; // not ERROR, so do not crash +        }  	}  } @@ -1541,29 +1553,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); diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index ffaa464d77..18d11cfa9d 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -193,14 +193,20 @@ namespace LLError  	*/  	struct CallSite; +	 +    enum ErrFatalHookResult { ERR_DO_NOT_CRASH, ERR_CRASH };  	class LL_COMMON_API Log  	{  	public:  		static bool shouldLog(CallSite&);  		static std::ostringstream* out(); +  		static void flush(std::ostringstream* out, char* message); -		static void flush(std::ostringstream*, const CallSite&); + +        // returns false iff the calling macro should crash +		static ErrFatalHookResult flush(std::ostringstream*, const CallSite&); +  		static std::string demangle(const char* mangled);  		/// classname<TYPE>()  		template <typename T> @@ -271,6 +277,7 @@ namespace LLError  	class LL_COMMON_API NoClassInfo { };  		// used to indicate no class info known for logging +      //LLCallStacks keeps track of call stacks and output the call stacks to log file      //when LLAppViewer::handleViewerCrash() is triggered.      // @@ -382,10 +389,24 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG;  #define LL_NEWLINE '\n' -#define LL_ENDL                               \ -			LLError::End();                   \ -			LLError::Log::flush(_out, _site); \ -		}                                     \ +#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       \ +{                           \ +    *gCauseCrash = 0;       \ +    exit(*gCauseCrash);     \ +} + +#define LL_ENDL                                          \ +			LLError::End();                              \ +            if (LLError::ERR_CRASH == LLError::Log::flush(_out, _site)) \ +                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 bfa2269025..d001a3bd03 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -93,40 +93,27 @@ namespace LLError  		Control functions.  	*/ -	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 +    // A FatalHook is called if set using setFatalHook; its return controls +    // whether or not the calling error logging code should crash. +    // ERR_DO_NOT_CRASH should be used only in test code. +	typedef boost::function<LLError::ErrFatalHookResult(const std::string&)> FatalHook; + +	/// Supplement and control the default behavior of crashing on LL_ERRS +    /// This may be used to suppress crashes only in test code; +    /// otherwise, the FatalHook should always either return  +    /// the result from the previous hook (see getFatalHook below), +    /// or return LLError::ERR_CRASH +	LL_COMMON_API void setFatalHook(const FatalHook& fatal_hook); +		// The fatal_hook 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. +		// (by, for example, setting a class level to LEVEL_NONE), will also +		// prevent the fatal_hook being called and the resulting deliberate crash -	LL_COMMON_API FatalFunction getFatalFunction(); -		// Retrieve the previously-set FatalFunction +    /// Retrieve the previously-set FatalHook +	LL_COMMON_API FatalHook getFatalHook();  	LL_COMMON_API std::string getFatalMessage(); -		// Retrieve the message last passed to FatalFunction, if any - -	/// temporarily override the FatalFunction for the duration of a -	/// particular scope, e.g. for unit tests -	class LL_COMMON_API OverrideFatalFunction -	{ -	public: -		OverrideFatalFunction(const FatalFunction& func): -			mPrev(getFatalFunction()) -		{ -			setFatalFunction(func); -		} -		~OverrideFatalFunction() -		{ -			setFatalFunction(mPrev); -		} - -	private: -		FatalFunction mPrev; -	}; +		// Retrieve the message last passed to LL_ERRS, if any  	typedef std::string (*TimeFunction)();  	LL_COMMON_API std::string utcTime(); diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index cf8f8cc6a5..8293c35516 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 @@ -145,9 +144,6 @@ public:          mStderrConnection = childerr.getPump()              .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)); -          // Send child a preliminary event reporting our own reply-pump name --          // which would otherwise be pretty tricky to guess!          wstdin(mReplyPump.getName(), @@ -162,8 +158,6 @@ public:      virtual ~LLLeapImpl()      {          LL_DEBUGS("LLLeap") << "destroying LLLeap(\"" << mDesc << "\")" << LL_ENDL; -        // Restore original FatalFunction -        LLError::setFatalFunction(mPrevFatalFunction);      }      // Listener for failed launch attempt @@ -377,30 +371,6 @@ public:          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); -        } - -        // forward the call to the previous FatalFunction -        mPrevFatalFunction(error); -    } -  private:      /// We always want to listen on mReplyPump with wstdin(); under some      /// circumstances we'll also echo other LLEventPumps to the plugin. @@ -421,7 +391,6 @@ private:          mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;      boost::scoped_ptr<LLEventPump::Blocker> mBlocker;      LLProcess::ReadPipe::size_type mExpect; -    LLError::FatalFunction mPrevFatalFunction;      boost::scoped_ptr<LLLeapListener> mListener;  }; diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index d3d25201b2..f410bd6a92 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -512,15 +512,7 @@ void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, co      // 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()); -    } +    LLERROR_CRASH;  }  std::string LLSingletonBase::demangle(const char* mangled) diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 8e1f4c14ac..cdc2bf8c87 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -70,7 +70,11 @@ namespace  namespace  {  	static bool fatalWasCalled; -	void fatalCall(const std::string&) { fatalWasCalled = true; } +    LLError::ErrFatalHookResult fatalHook(const std::string&) +    { +        fatalWasCalled = true; +        return LLError::ERR_DO_NOT_CRASH; +    }  }  namespace tut @@ -120,7 +124,7 @@ namespace tut  			mPriorErrorSettings = LLError::saveAndResetSettings();  			LLError::setDefaultLevel(LLError::LEVEL_DEBUG); -			LLError::setFatalFunction(fatalCall); +			LLError::setFatalHook(fatalHook);  			LLError::addRecorder(mRecorder);  		} @@ -777,30 +781,33 @@ namespace tut  		// proper cached, efficient lookup of filtering  	void ErrorTestObject::test<15>()  	{ -		LLError::setDefaultLevel(LLError::LEVEL_NONE); +		LLError::setDefaultLevel(LLError::LEVEL_NONE);  + +        // Note that the setFatalHook in the ErrorTestData constructor +        // increments the shouldLogCallCount  		TestAlpha::doInfo();  		ensure_message_count(0); -		ensure_equals("first check", LLError::shouldLogCallCount(), 1); +		ensure_equals("first check", LLError::shouldLogCallCount(), 2);  		TestAlpha::doInfo();  		ensure_message_count(0); -		ensure_equals("second check", LLError::shouldLogCallCount(), 1); +		ensure_equals("second check", LLError::shouldLogCallCount(), 2);  		LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG);  		TestAlpha::doInfo();  		ensure_message_count(1); -		ensure_equals("third check", LLError::shouldLogCallCount(), 2); +		ensure_equals("third check", LLError::shouldLogCallCount(), 3);  		TestAlpha::doInfo();  		ensure_message_count(2); -		ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); +		ensure_equals("fourth check", LLError::shouldLogCallCount(), 3);  		LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN);  		TestAlpha::doInfo();  		ensure_message_count(2); -		ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); +		ensure_equals("fifth check", LLError::shouldLogCallCount(), 4);  		TestAlpha::doInfo();  		ensure_message_count(2); -		ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); +		ensure_equals("sixth check", LLError::shouldLogCallCount(), 4);  	}  	template<> template<> diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index b07d5afbd8..a6c44d5fdd 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -46,25 +46,24 @@  // statically reference the function in test.cpp... it's short, we could  // replicate, but better to reuse -extern void wouldHaveCrashed(const std::string& message); +extern LLError::ErrFatalHookResult 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()), -        // Save shutdown function called by LL_ERRS -        mPriorFatal(LLError::getFatalFunction()) +    :mPriorErrorSettings(LLError::saveAndResetSettings()) +    ,mPriorFatalHook(LLError::getFatalHook())      {          // Make LL_ERRS call our own operator() method -        LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1)); +        LLError::setFatalHook(boost::bind(&WrapLLErrs::operator(), this, _1));      }      ~WrapLLErrs()      { -        LLError::setFatalFunction(mPriorFatal); +        LLError::setFatalHook(mPriorFatalHook);          LLError::restoreSettings(mPriorErrorSettings);      } @@ -73,7 +72,7 @@ struct WrapLLErrs          FatalException(const std::string& what): LLException(what) {}      }; -    void operator()(const std::string& message) +    LLError::ErrFatalHookResult operator()(const std::string& message)      {          // Save message for later in case consumer wants to sense the result directly          error = message; @@ -109,7 +108,7 @@ struct WrapLLErrs      std::string error;      LLError::SettingsStoragePtr mPriorErrorSettings; -    LLError::FatalFunction mPriorFatal; +    LLError::FatalHook mPriorFatalHook;  };  /** @@ -199,11 +198,12 @@ 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(), -        mOldSettings(LLError::saveAndResetSettings()), -		mRecorder(new CaptureLogRecorder()) +		: boost::noncopyable() +        , mOldSettings(LLError::saveAndResetSettings()) +		, mPriorFatalHook(LLError::getFatalHook()) +		, mRecorder(new CaptureLogRecorder())      { -        LLError::setFatalFunction(wouldHaveCrashed); +        LLError::setFatalHook(wouldHaveCrashed);          LLError::setDefaultLevel(level);          LLError::addRecorder(mRecorder);      } @@ -212,6 +212,7 @@ public:      {          LLError::removeRecorder(mRecorder);          LLError::restoreSettings(mOldSettings); +        LLError::setFatalHook(mPriorFatalHook);      }      /// Don't assume the message we want is necessarily the LAST log message @@ -229,6 +230,7 @@ public:  private:      LLError::SettingsStoragePtr mOldSettings; +    LLError::FatalHook   mPriorFatalHook;  	LLError::RecorderPtr mRecorder;  }; diff --git a/indra/llcorehttp/CMakeLists.txt b/indra/llcorehttp/CMakeLists.txt index 11b2e3e929..8efaf75582 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 88667bdc11..a4cbe73e8a 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 @@ -1406,11 +1404,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 @@ -1738,10 +1736,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 @@ -1818,9 +1816,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 @@ -1875,10 +1876,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) @@ -2029,11 +2031,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.") @@ -2044,13 +2046,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} @@ -2178,8 +2183,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}") @@ -2221,7 +2229,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) @@ -2238,7 +2246,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) @@ -2276,7 +2284,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 @@ -2360,9 +2368,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 47fde299c7..ccab9173a9 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; @@ -299,9 +301,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 75574df00e..581e69ec40 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -723,14 +723,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); @@ -755,17 +755,7 @@ 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); -} - - -} - +static S32 sQAModeTermCode = 0; // set from QAModeTermCode to specify exit code for LL_ERRS  bool LLAppViewer::init()  { @@ -809,18 +799,8 @@ bool LLAppViewer::init()  	initMaxHeapSize() ;  	LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); - -	// Although initLoggingAndGetLastDuration() is the right place to mess with -	// setFatalFunction(), 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::setFatalFunction(boost::bind(fast_exit, rc)); -	} +    // if a return code is set for error exit, save it here for use in fatalErrorHandler +    sQAModeTermCode = gSavedSettings.getS32("QAModeTermCode");      mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); @@ -2142,28 +2122,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; @@ -2198,7 +2156,7 @@ bool LLAppViewer::initThreads()  	return true;  } -void errorCallback(const std::string &error_string) +LLError::ErrFatalHookResult fatalErrorHook(const std::string &error_string)  {  #ifndef LL_RELEASE_FOR_DOWNLOAD  	OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK); @@ -2213,8 +2171,10 @@ void errorCallback(const std::string &error_string)  	// static info file.  	LLAppViewer::instance()->writeDebugInfo(); -#ifndef SHADER_CRASH_NONFATAL -	LLError::crashAndLoop(error_string); +#ifdef SHADER_CRASH_NONFATAL +	return LLError::ERR_DO_NOT_CRASH; +#else +    return LLError::ERR_CRASH;  #endif  } @@ -2226,8 +2186,8 @@ void LLAppViewer::initLoggingAndGetLastDuration()  	LLError::initForApplication( gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "")                                  ,gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")                                  ); -	LLError::setFatalFunction(errorCallback); -	//LLError::setTimeFunction(getRuntime); + +    // TBD fatal hook belongs here  	// Remove the last ".old" log file.  	std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, @@ -2289,6 +2249,10 @@ void LLAppViewer::initLoggingAndGetLastDuration()  	{  		LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;  	} + +    // TBD - temporary location for fatal hook (should be above, but for now it logs...) +    LL_DEBUGS("FatalHook") << "initial setting of default fatalhook" << LL_ENDL; +    LLError::setFatalHook(fatalErrorHook);  }  bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, @@ -2985,11 +2949,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(); @@ -3435,12 +3404,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; +#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 @@ -3668,6 +3643,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.  } @@ -3766,9 +3743,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  		{ @@ -5535,11 +5511,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 3111540a13..784a104573 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,17 +170,17 @@ 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; +        LL_INFOS("Bugsplat") << "Previous run metadata from '" << staticDebugPathname << "':" << LL_ENDL;          logFilePathname      = get_metadata(info, "SLLog");          userSettingsPathname = get_metadata(info, "SettingsFilename");          OSInfo               = get_metadata(info, "OSInfo"); @@ -218,7 +200,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 )  @@ -241,14 +223,11 @@ bool LLAppViewerMacOSX::init()  {  	bool success = LLAppViewer::init(); -#if LL_SEND_CRASH_REPORTS      if (success)      {          LLAppViewer* pApp = LLAppViewer::instance();          pApp->initCrashReporting();      } -#endif -          return success;  } @@ -333,11 +312,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) @@ -368,6 +348,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; @@ -379,6 +363,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() @@ -390,7 +377,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 156a1c5893..9f8b1745d4 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -174,7 +174,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  } @@ -362,10 +362,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); @@ -810,8 +806,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 0cc1e0df06..556f16e0b4 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 f5edde1923..2105b419e7 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1057,10 +1057,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/test/test.cpp b/indra/test/test.cpp index 87c4a8d8a3..b16fcb84d6 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -58,8 +58,7 @@  #include <gtest/gtest.h>  #endif -#if LL_MSVC -#pragma warning (push) +#if LL_WINDOWS  #pragma warning (disable : 4702) // warning C4702: unreachable code  #endif  #include <boost/iostreams/tee.hpp> @@ -75,7 +74,11 @@  #include <fstream> -void wouldHaveCrashed(const std::string& message); +LLError::ErrFatalHookResult wouldHaveCrashed(const std::string& message) +{ +	tut::fail("fatal error message: " + message); +    return LLError::ERR_DO_NOT_CRASH; +}  namespace tut  { @@ -146,7 +149,7 @@ public:  		mOldSettings(LLError::saveAndResetSettings()),  		mRecorder(new RecordToTempFile(pool))  	{ -		LLError::setFatalFunction(wouldHaveCrashed); +		LLError::setFatalHook(wouldHaveCrashed);  		LLError::setDefaultLevel(level);  		LLError::addRecorder(mRecorder);  	} @@ -512,11 +515,6 @@ void stream_groups(std::ostream& s, const char* app)  	}  } -void wouldHaveCrashed(const std::string& message) -{ -	tut::fail("llerrs message: " + message); -} -  static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL;  int main(int argc, char **argv) @@ -626,7 +624,7 @@ int main(int argc, char **argv)  			replayer.reset(new LLReplayLogReal(level, gAPRPoolp));  		}  	} -	LLError::setFatalFunction(wouldHaveCrashed); +	LLError::setFatalHook(wouldHaveCrashed);  	std::string test_app_name(argv[0]);  	std::string test_log = test_app_name + ".log";  	LLFile::remove(test_log); 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. | 
