From 2700f7994e0645c11ab32bf9239ab6c215faec67 Mon Sep 17 00:00:00 2001 From: Nicky Date: Sun, 7 Feb 2016 23:47:58 +0100 Subject: [PATCH] FIRE-17517; LD_PRELOAD libcef.so when launching a plugin that will dso-load media_plugin_cef. Reasoning is that libcef.so is bild with tcmalloc and thus will cause all kind of havok if not preloaded. Hopefully cefbuilds will stop doing this soon enough (see https://bitbucket.org/chromiumembedded/cef/issues/1827) and this can be reverted. Alternative is to rebuild CEF each and every time for x86 and x64 when it is updated. See also: http://jira.phoenixviewer.com/browse/FIRE-17517 https://lists.secondlife.com/pipermail/opensource-dev/2015-July/010106.html https://bitbucket.org/chromiumembedded/cef/issues/1827/tcmalloc-should-be-disabled-in-linux-osx --- indra/llcommon/llprocess.cpp | 39 ++++++++++++++++++++++++ indra/llcommon/llprocess.h | 9 ++++++ indra/llplugin/llpluginprocessparent.cpp | 8 +++++ indra/newview/linux_tools/wrapper.sh | 2 ++ 4 files changed, 58 insertions(+) diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index e0aa30cc1a..2815293a67 100755 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -507,6 +507,40 @@ LLProcessPtr LLProcess::create(const LLSDOrParams& params) } } +// Annoying preload hack to make tcmalloc in libcef.so play nicely. +std::string installPreloadHack( std::string const &preload ) +{ + std::string strOldPreload; +#ifdef LL_LINUX + if( preload.size() ) + { + std::string strPreload = preload; + if( getenv( "LD_PRELOAD" ) ) + { + strOldPreload = getenv( "PRELOAD" ); + strPreload = ":" + strOldPreload; + } + + setenv( "LD_PRELOAD", strPreload.c_str(), 1 ); + } +#endif + return strOldPreload; +} + +void uninstallPreloadHack( std::string const &preload, std::string const &strOldPreload ) +{ +#ifdef LL_LINUX + if( preload.empty() ) + return; + + if( strOldPreload.size() ) + setenv( "LD_PRELOAD", strOldPreload.c_str(), 1 ); + else + unsetenv( "LD_PRELOAD" ); +#endif +} +// + /// Call an apr function returning apr_status_t. On failure, log warning and /// throw LLProcessError mentioning the function call that produced that /// result. @@ -672,15 +706,20 @@ LLProcess::LLProcess(const LLSDOrParams& params): // terminate with a null pointer argv.push_back(NULL); + std::string strOldPreload = installPreloadHack( params.preload ); // FS:ND/> Install preload hack (if needed) + // Launch! The NULL would be the environment block, if we were passing // one. Hand-expand chkapr() macro so we can fill in the actual command // string instead of the variable names. if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, gAPRPoolp))) { + uninstallPreloadHack( params.preload, strOldPreload ); // Remove preload hack throw LLProcessError(STRINGIZE(params << " failed")); } + uninstallPreloadHack( params.preload, strOldPreload ); // Remove preload hack + // arrange to call status_callback() apr_proc_other_child_register(&mProcess, &LLProcess::status_callback, this, mProcess.in, gAPRPoolp); diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 43ccadc412..80d416bd01 100755 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -227,6 +227,15 @@ public: * executable name. */ Optional desc; + + /** + HACK! libcef.so bleeds that intrusive tcmalloc hacks all over the process. + This then causes awesome effects like crashes and memory corruption when the so is loaded dynamically. + We uses this argument to force libcef.so be preloaded, which fixes this. + The other solution would be to recompile CEF twice (x86/x64) for each CEF update. Which I really would like to avoid. + */ + Optional preload; + }; typedef LLSDParamAdapter LLSDOrParams; diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index 6a69d5fda0..0ef5abef32 100755 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -480,6 +480,14 @@ void LLPluginProcessParent::idle(void) // Only argument to the launcher is the port number we're listening on mProcessParams.args.add(stringize(mBoundPort)); +#if LL_LINUX + if( mPluginFile.find( "cef" ) != std::string::npos && getenv( "FS_CEF_PRELOAD" ) ) + { + mProcessParams.preload = getenv( "FS_CEF_PRELOAD" ); + LL_INFOS( "Plugin" ) << "Forcing LD_PRELOAD for " << (std::string)mProcessParams.executable << " with a value of " << (std::string)mProcessParams.preload << LL_ENDL; + } +#endif + if (! (mProcess = LLProcess::create(mProcessParams))) { errorState(); diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 19cc99c7cc..df7fae834c 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -162,6 +162,8 @@ fi fi +export FS_CEF_PRELOAD="`pwd`/lib/libcef.so" + # Copy "$@" to ARGS array specifically to delete the --skip-gridargs switch. # The gridargs.dat file is no more, but we still want to avoid breaking # scripts that invoke this one with --skip-gridargs.