Author: enrico Date: Fri Feb 5 18:43:07 2016 New Revision: 259964 URL: http://llvm.org/viewvc/llvm-project?rev=259964&view=rev Log: Fix an issue where certain CommandObjects (or Options thereof) were being created once, bound to a specific CommandInterpreter (and hence a specific Debugger), and then cached for reuse across different Debugger instances
Obviously, if the original Debugger goes away, those commands are holding on to now stale memory, which has the potential to cause crashes Fixes rdar://24460882 Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/ lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py Modified: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h lldb/trunk/source/Target/LanguageRuntime.cpp Added: lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py?rev=259964&view=auto ============================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py (added) +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/multidebugger_commands/TestMultipleDebuggersCommands.py Fri Feb 5 18:43:07 2016 @@ -0,0 +1,48 @@ +""" +Test that commands do not try and hold on to stale CommandInterpreters in a multiple debuggers scenario +""" + +from __future__ import print_function + + + +import os, time +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class MultipleDebuggersCommandsTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @no_debug_info_test + def test_multipledebuggers_commands(self): + """Test that commands do not try and hold on to stale CommandInterpreters in a multiple debuggers scenario""" + source_init_files = False + magic_text = "The following built-in commands may relate to 'env'" + + debugger_1 = lldb.SBDebugger.Create(source_init_files) + interpreter_1 = debugger_1.GetCommandInterpreter() + + retobj = lldb.SBCommandReturnObject() + interpreter_1.HandleCommand("apropos env", retobj) + self.assertTrue(magic_text in str(retobj), "[interpreter_1]: the output does not contain the correct words") + + if self.TraceOn(): print(str(retobj)) + + lldb.SBDebugger.Destroy(debugger_1) + + # now do this again with a different debugger - we shouldn't crash + + debugger_2 = lldb.SBDebugger.Create(source_init_files) + interpreter_2 = debugger_2.GetCommandInterpreter() + + retobj = lldb.SBCommandReturnObject() + interpreter_2.HandleCommand("apropos env", retobj) + self.assertTrue(magic_text in str(retobj), "[interpreter_2]: the output does not contain the correct words") + + if self.TraceOn(): print(str(retobj)) + + lldb.SBDebugger.Destroy(debugger_2) + Modified: lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp?rev=259964&r1=259963&r2=259964&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp Fri Feb 5 18:43:07 2016 @@ -4167,12 +4167,7 @@ RenderScriptRuntime::RenderScriptRuntime lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter &interpreter) { - static CommandObjectSP command_object; - if (!command_object) - { - command_object.reset(new CommandObjectRenderScriptRuntime(interpreter)); - } - return command_object; + return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); } RenderScriptRuntime::~RenderScriptRuntime() = default; Modified: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp?rev=259964&r1=259963&r2=259964&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp (original) +++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp Fri Feb 5 18:43:07 2016 @@ -41,6 +41,9 @@ using namespace lldb_private; //------------------------------------------------------------------ PlatformPOSIX::PlatformPOSIX (bool is_host) : Platform(is_host), // This is the local host platform +m_option_group_platform_rsync(new OptionGroupPlatformRSync()), +m_option_group_platform_ssh(new OptionGroupPlatformSSH()), +m_option_group_platform_caching(new OptionGroupPlatformCaching()), m_remote_platform_sp () { } @@ -69,14 +72,17 @@ PlatformPOSIX::GetModuleSpec (const File lldb_private::OptionGroupOptions* PlatformPOSIX::GetConnectionOptions (lldb_private::CommandInterpreter& interpreter) { - if (m_options.get() == NULL) + auto iter = m_options.find(&interpreter), end = m_options.end(); + if (iter == end) { - m_options.reset(new OptionGroupOptions(interpreter)); - m_options->Append(new OptionGroupPlatformRSync()); - m_options->Append(new OptionGroupPlatformSSH()); - m_options->Append(new OptionGroupPlatformCaching()); + std::unique_ptr<lldb_private::OptionGroupOptions> options(new OptionGroupOptions(interpreter)); + options->Append(m_option_group_platform_rsync.get()); + options->Append(m_option_group_platform_ssh.get()); + options->Append(m_option_group_platform_caching.get()); + m_options[&interpreter] = std::move(options); } - return m_options.get(); + + return m_options.at(&interpreter).get(); } bool @@ -675,29 +681,21 @@ PlatformPOSIX::ConnectRemote (Args& args if (error.Success() && m_remote_platform_sp) { - if (m_options.get()) + if (m_option_group_platform_rsync.get() && m_option_group_platform_ssh.get() && m_option_group_platform_caching.get()) { - OptionGroupOptions* options = m_options.get(); - const OptionGroupPlatformRSync *m_rsync_options = - static_cast<const OptionGroupPlatformRSync *>(options->GetGroupWithOption('r')); - const OptionGroupPlatformSSH *m_ssh_options = - static_cast<const OptionGroupPlatformSSH *>(options->GetGroupWithOption('s')); - const OptionGroupPlatformCaching *m_cache_options = - static_cast<const OptionGroupPlatformCaching *>(options->GetGroupWithOption('c')); - - if (m_rsync_options->m_rsync) + if (m_option_group_platform_rsync->m_rsync) { SetSupportsRSync(true); - SetRSyncOpts(m_rsync_options->m_rsync_opts.c_str()); - SetRSyncPrefix(m_rsync_options->m_rsync_prefix.c_str()); - SetIgnoresRemoteHostname(m_rsync_options->m_ignores_remote_hostname); + SetRSyncOpts(m_option_group_platform_rsync->m_rsync_opts.c_str()); + SetRSyncPrefix(m_option_group_platform_rsync->m_rsync_prefix.c_str()); + SetIgnoresRemoteHostname(m_option_group_platform_rsync->m_ignores_remote_hostname); } - if (m_ssh_options->m_ssh) + if (m_option_group_platform_ssh->m_ssh) { SetSupportsSSH(true); - SetSSHOpts(m_ssh_options->m_ssh_opts.c_str()); + SetSSHOpts(m_option_group_platform_ssh->m_ssh_opts.c_str()); } - SetLocalCacheDirectory(m_cache_options->m_cache_dir.c_str()); + SetLocalCacheDirectory(m_option_group_platform_caching->m_cache_dir.c_str()); } } Modified: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h?rev=259964&r1=259963&r2=259964&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h (original) +++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h Fri Feb 5 18:43:07 2016 @@ -12,6 +12,7 @@ // C Includes // C++ Includes +#include <map> #include <memory> // Other libraries and framework includes @@ -192,7 +193,11 @@ public: ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; protected: - std::unique_ptr<lldb_private::OptionGroupOptions> m_options; + std::unique_ptr<lldb_private::OptionGroupPlatformRSync> m_option_group_platform_rsync; + std::unique_ptr<lldb_private::OptionGroupPlatformSSH> m_option_group_platform_ssh; + std::unique_ptr<lldb_private::OptionGroupPlatformCaching> m_option_group_platform_caching; + + std::map<lldb_private::CommandInterpreter*,std::unique_ptr<lldb_private::OptionGroupOptions>> m_options; lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS lldb_private::Error Modified: lldb/trunk/source/Target/LanguageRuntime.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/LanguageRuntime.cpp?rev=259964&r1=259963&r2=259964&view=diff ============================================================================== --- lldb/trunk/source/Target/LanguageRuntime.cpp (original) +++ lldb/trunk/source/Target/LanguageRuntime.cpp Fri Feb 5 18:43:07 2016 @@ -336,6 +336,10 @@ LanguageRuntime::InitializeCommands (Com CommandObjectSP command = command_callback(parent->GetCommandInterpreter()); if (command) { + // the CommandObject vended by a Language plugin cannot be created once and cached because + // we may create multiple debuggers and need one instance of the command each - the implementing function + // is meant to create a new instance of the command each time it is invoked + assert(&command->GetCommandInterpreter() == &parent->GetCommandInterpreter() && "language plugin returned command for a mismatched CommandInterpreter"); parent->LoadSubCommand(command->GetCommandName(), command); } } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits