From c5f618d096f05bdff91a5d384c46e26840f5a771 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 06:53:42 -0400 Subject: SL-821: Move Windows BugSplat engagement from llcommon to newview. Use WSTRINGIZE(), LL_TO_WSTRING(), wstringize() to produce required wide strings. Use a lambda for callback that sends log file; use LLDir, if set, to find the log file. Introduce BUGSPLAT CMake variable to allow suppressing BugSplat. Make BUGSPLAT CMake variable set LL_BUGSPLAT for C++ compilations. Set viewer version macros on llappviewerwin32.cpp, llappviewerlinux.cpp and llappdelegate-objc.mm -- because BugSplat needs the viewer version data, and because the macOS BugSplat hook is engaged in an Objective-C++ function we override in the app delegate. --- indra/newview/llappviewerwin32.cpp | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 48b3a1c485..8a014c55d7 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -66,8 +66,18 @@ #endif #include "stringize.h" +#include "lldir.h" #include + +// Bugsplat (http://bugsplat.com) crash reporting tool +#ifdef LL_BUGSPLAT +#include "BugSplat.h" + +// FIXME: need a production BugSplat database name +static const wchar_t *bugdb_name = L"second_life_callum_test"; +#endif + namespace { void (*gOldTerminateHandler)() = NULL; @@ -495,15 +505,46 @@ bool LLAppViewerWin32::init() LLWinDebug::instance(); #endif -#if LL_WINDOWS #if LL_SEND_CRASH_REPORTS - +#if ! defined(LL_BUGSPLAT) LLAppViewer* pApp = LLAppViewer::instance(); pApp->initCrashReporting(); -#endif -#endif +#else // LL_BUGSPLAT + + std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << + LL_VIEWER_VERSION_MINOR << '.' << + LL_VIEWER_VERSION_PATCH << '.' << + LL_VIEWER_VERSION_BUILD)); + + auto sender = new MiniDmpSender( + bugdb_name, LL_TO_WSTRING(LL_VIEWER_CHANNEL), version_string.c_str(), nullptr); + sender->setCallback( + [sender](unsigned int nCode, void* lpVal1, void* lpVal2) + { + // If we haven't yet initialized LLDir, don't bother trying to + // find our log file. + // Alternatively -- if we might encounter trouble trying to query + // LLDir during crash cleanup -- consider making gDirUtilp an + // LLPounceable, and attach a callback that stores the pathname to + // the log file here. + if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + { + // send the main viewer log file + // widen to wstring, then pass c_str() + sender->sendAdditionalFile( + wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); + } + + return false; + }); + + LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + << version_string << ')' << LL_ENDL; + +#endif // LL_BUGSPLAT +#endif // LL_SEND_CRASH_REPORTS bool success = LLAppViewer::init(); -- cgit v1.2.3 From cd21556aef547dbb031e363d3a9b9f1893be4d08 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 10:58:59 -0400 Subject: SL-821: Convert wstrings to strings of __wchar_t for BugSplat API. --- indra/newview/llappviewerwin32.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 8a014c55d7..91c6f08000 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -76,7 +76,14 @@ // FIXME: need a production BugSplat database name static const wchar_t *bugdb_name = L"second_life_callum_test"; -#endif + +// MiniDmpSender's constructor is defined to accept __wchar_t* instead of +// plain wchar_t*. +inline std::basic_string<__wchar_t> wunder(const std::wstring& str) +{ + return { str.begin(), str.end() }; +} +#endif // LL_BUGSPLAT namespace { @@ -518,8 +525,12 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD)); + // have to convert normal wide strings to strings of __wchar_t auto sender = new MiniDmpSender( - bugdb_name, LL_TO_WSTRING(LL_VIEWER_CHANNEL), version_string.c_str(), nullptr); + wunder(bugdb_name).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); sender->setCallback( [sender](unsigned int nCode, void* lpVal1, void* lpVal2) { @@ -532,16 +543,17 @@ bool LLAppViewerWin32::init() if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) { // send the main viewer log file - // widen to wstring, then pass c_str() + // widen to wstring, convert to __wchar_t, then pass c_str() sender->sendAdditionalFile( - wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); + wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); } return false; }); + // engage stringize() overload that converts from wstring LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << version_string << ')' << LL_ENDL; + << stringize(version_string) << ')' << LL_ENDL; #endif // LL_BUGSPLAT #endif // LL_SEND_CRASH_REPORTS -- cgit v1.2.3 From 800b47ec230d1d2a6781dce5ba9816d10a37e91e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 May 2018 15:02:26 -0400 Subject: SL-821: Use classic-C BugSplat callback and static dumb pointer. BugSplat has no business introducing a new C++ API based on classic-C function pointers without even a generic pass-through user data pointer! --- indra/newview/llappviewerwin32.cpp | 65 ++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 91c6f08000..5f3bf14bc2 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -74,14 +74,43 @@ #ifdef LL_BUGSPLAT #include "BugSplat.h" -// FIXME: need a production BugSplat database name -static const wchar_t *bugdb_name = L"second_life_callum_test"; - -// MiniDmpSender's constructor is defined to accept __wchar_t* instead of -// plain wchar_t*. -inline std::basic_string<__wchar_t> wunder(const std::wstring& str) +namespace { - return { str.begin(), str.end() }; + // FIXME: need a production BugSplat database name + static const wchar_t *bugdb_name = L"second_life_callum_test"; + + // MiniDmpSender's constructor is defined to accept __wchar_t* instead of + // plain wchar_t*. + inline std::basic_string<__wchar_t> wunder(const std::wstring& str) + { + return { str.begin(), str.end() }; + } + + // Irritatingly, MiniDmpSender::setCallback() is defined to accept a + // classic-C function pointer instead of an arbitrary C++ callable. In the + // latter case, we could pass a lambda that binds our MiniDmpSender + // pointer. As things stand, we must define an actual function and store + // the pointer statically. + static MiniDmpSender *sBugSplatSender = nullptr; + + bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) + { + // If we haven't yet initialized LLDir, don't bother trying to + // find our log file. + // Alternatively -- if we might encounter trouble trying to query + // LLDir during crash cleanup -- consider making gDirUtilp an + // LLPounceable, and attach a callback that stores the pathname to + // the log file here. + if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + { + // send the main viewer log file + // widen to wstring, convert to __wchar_t, then pass c_str() + sBugSplatSender->sendAdditionalFile( + wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); + } + + return false; + } } #endif // LL_BUGSPLAT @@ -526,30 +555,12 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_BUILD)); // have to convert normal wide strings to strings of __wchar_t - auto sender = new MiniDmpSender( + sBugSplatSender = new MiniDmpSender( wunder(bugdb_name).c_str(), wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), wunder(version_string).c_str(), nullptr); - sender->setCallback( - [sender](unsigned int nCode, void* lpVal1, void* lpVal2) - { - // If we haven't yet initialized LLDir, don't bother trying to - // find our log file. - // Alternatively -- if we might encounter trouble trying to query - // LLDir during crash cleanup -- consider making gDirUtilp an - // LLPounceable, and attach a callback that stores the pathname to - // the log file here. - if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) - { - // send the main viewer log file - // widen to wstring, convert to __wchar_t, then pass c_str() - sender->sendAdditionalFile( - wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); - } - - return false; - }); + sBugSplatSender->setCallback(bugsplatSendLog); // engage stringize() overload that converts from wstring LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) -- cgit v1.2.3 From 63fe7d802aad177107ef8e3bc0c9b7ea5118ad61 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 25 May 2018 12:09:50 -0400 Subject: SL-821, SL-826: Use BUGSPLAT_DB from environment on Windows and Mac. On TeamCity, set BUGSPLAT_DB from build-secrets. Use the presence of $BUGSPLAT_DB, rather than a new CMake BUGSPLAT option, to control whether CMake searches for BugSplat -- and passes LL_BUGSPLAT into C++. When BUGSPLAT_DB is present, make viewer_manifest.py set "BugSplat DB" in build_data.json, and "BugsplatServerURL" in Mac Info.plist. Make llappviewerwin32.cpp read "BugSplat DB" from build_data.json. Add placeholders for Mac hooks to suppress BugSplat prompt and send SecondLife.log. --- indra/newview/llappviewerwin32.cpp | 87 +++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 24 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 5f3bf14bc2..f9df2b88ed 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -68,29 +68,30 @@ #include "stringize.h" #include "lldir.h" +#include #include // Bugsplat (http://bugsplat.com) crash reporting tool #ifdef LL_BUGSPLAT #include "BugSplat.h" +#include "reader.h" // JsonCpp namespace { - // FIXME: need a production BugSplat database name - static const wchar_t *bugdb_name = L"second_life_callum_test"; - // MiniDmpSender's constructor is defined to accept __wchar_t* instead of - // plain wchar_t*. + // plain wchar_t*. It would be nice if, when wchar_t is the same as + // __wchar_t, this whole function would optimize away. However, we use it + // only for the arguments to make exactly one call to initialize BugSplat. inline std::basic_string<__wchar_t> wunder(const std::wstring& str) { return { str.begin(), str.end() }; } // Irritatingly, MiniDmpSender::setCallback() is defined to accept a - // classic-C function pointer instead of an arbitrary C++ callable. In the - // latter case, we could pass a lambda that binds our MiniDmpSender - // pointer. As things stand, we must define an actual function and store - // the pointer statically. + // classic-C function pointer instead of an arbitrary C++ callable. If it + // did accept a modern callable, we could pass a lambda that binds our + // MiniDmpSender pointer. As things stand, though, we must define an + // actual function and store the pointer statically. static MiniDmpSender *sBugSplatSender = nullptr; bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) @@ -549,22 +550,60 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT - std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << - LL_VIEWER_VERSION_MINOR << '.' << - LL_VIEWER_VERSION_PATCH << '.' << - LL_VIEWER_VERSION_BUILD)); - - // have to convert normal wide strings to strings of __wchar_t - sBugSplatSender = new MiniDmpSender( - wunder(bugdb_name).c_str(), - wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), - wunder(version_string).c_str(), - nullptr); - sBugSplatSender->setCallback(bugsplatSendLog); - - // engage stringize() overload that converts from wstring - LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) - << stringize(version_string) << ')' << LL_ENDL; + if (gDirUtilp) + { + LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL; + } + else + { + std::string build_data_fname( + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + std::ifstream inf(build_data_fname.c_str()); + if (! inf.open()) + { + LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname + << "'" << LL_ENDL; + } + else + { + Json::Reader reader; + Json::Value build_data; + if (! reader.parse(inf, build_data, false)) // don't collect comments + { + LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + << "': " << reader.getFormattedErrorMessages() << LL_ENDL; + } + else + { + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if (! BugSplat_DB) + { + LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" + << build_data_fname "'" << LL_ENDL; + } + else + { + // Got BugSplat_DB, onward! + std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << + LL_VIEWER_VERSION_MINOR << '.' << + LL_VIEWER_VERSION_PATCH << '.' << + LL_VIEWER_VERSION_BUILD)); + + // have to convert normal wide strings to strings of __wchar_t + sBugSplatSender = new MiniDmpSender( + wunder(BugSplat_DB).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); + sBugSplatSender->setCallback(bugsplatSendLog); + + // engage stringize() overload that converts from wstring + LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + << stringize(version_string) << ')' << LL_ENDL; + } // got BugSplat_DB + } // parsed build_data.json + } // opened build_data.json + } // gDirUtilp set #endif // LL_BUGSPLAT #endif // LL_SEND_CRASH_REPORTS -- cgit v1.2.3 From 3ca76065b0beeaf276078b4bc28b8e0c6295a4fc Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 25 May 2018 19:02:53 -0400 Subject: SL-823: Fix minor compile errors in code to read build_data.json. --- indra/newview/llappviewerwin32.cpp | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f9df2b88ed..b7ad28448b 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -79,14 +79,29 @@ namespace { // MiniDmpSender's constructor is defined to accept __wchar_t* instead of - // plain wchar_t*. It would be nice if, when wchar_t is the same as - // __wchar_t, this whole function would optimize away. However, we use it - // only for the arguments to make exactly one call to initialize BugSplat. + // plain wchar_t*. That said, wunder() returns std::basic_string<__wchar_t>, + // NOT plain __wchar_t*, despite the apparent convenience. Calling + // wunder(something).c_str() as an argument expression is fine: that + // std::basic_string instance will survive until the function returns. + // Calling c_str() on a std::basic_string local to wunder() would be + // Undefined Behavior: we'd be left with a pointer into a destroyed + // std::basic_string instance. + + // It would be nice if, when wchar_t is the same as __wchar_t, this whole + // function would optimize away. However, we use it only for the arguments + // to make exactly one call to initialize BugSplat. inline std::basic_string<__wchar_t> wunder(const std::wstring& str) { return { str.begin(), str.end() }; } + // when what we have in hand is a std::string, convert from UTF-8 using + // specific wstringize() overload + inline std::basic_string<__wchar_t> wunder(const std::string& str) + { + return wunder(wstringize(str)); + } + // Irritatingly, MiniDmpSender::setCallback() is defined to accept a // classic-C function pointer instead of an arbitrary C++ callable. If it // did accept a modern callable, we could pass a lambda that binds our @@ -107,7 +122,7 @@ namespace // send the main viewer log file // widen to wstring, convert to __wchar_t, then pass c_str() sBugSplatSender->sendAdditionalFile( - wunder(wstringize(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log"))).c_str()); + wunder(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); } return false; @@ -559,7 +574,7 @@ bool LLAppViewerWin32::init() std::string build_data_fname( gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); std::ifstream inf(build_data_fname.c_str()); - if (! inf.open()) + if (! inf.is_open()) { LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname << "'" << LL_ENDL; @@ -570,8 +585,9 @@ bool LLAppViewerWin32::init() Json::Value build_data; if (! reader.parse(inf, build_data, false)) // don't collect comments { + // gah, the typo is baked into their API LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname - << "': " << reader.getFormattedErrorMessages() << LL_ENDL; + << "': " << reader.getFormatedErrorMessages() << LL_ENDL; } else { @@ -579,7 +595,7 @@ bool LLAppViewerWin32::init() if (! BugSplat_DB) { LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" - << build_data_fname "'" << LL_ENDL; + << build_data_fname << "'" << LL_ENDL; } else { @@ -591,7 +607,7 @@ bool LLAppViewerWin32::init() // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( - wunder(BugSplat_DB).c_str(), + wunder(BugSplat_DB.asString()).c_str(), wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), wunder(version_string).c_str(), nullptr); -- cgit v1.2.3 From a5c17472fb3bbd2bc6fe188c450d2123963b5d6e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 26 May 2018 08:44:57 -0400 Subject: SL-823: Fix typo in code that sets up BugSplat. --- indra/newview/llappviewerwin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llappviewerwin32.cpp') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f9df2b88ed..c2cbce493c 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -550,7 +550,7 @@ bool LLAppViewerWin32::init() #else // LL_BUGSPLAT - if (gDirUtilp) + if (! gDirUtilp) { LL_WARNS() << "Can't initialize BugSplat, gDirUtilp not yet set" << LL_ENDL; } -- cgit v1.2.3