llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) <details> <summary>Changes</summary> While debugging the flakiness of the launch and attach tests, I noticed that we have some places in lldb-dap where we put the debugger in synchronous mode and have an early exit, that would leave the debugger in this state. This PR introduces an RAII helper to avoid such mistakes. --- Full diff: https://github.com/llvm/llvm-project/pull/137900.diff 6 Files Affected: - (modified) lldb/tools/lldb-dap/DAP.cpp (+3-3) - (modified) lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp (+6-4) - (modified) lldb/tools/lldb-dap/Handler/RequestHandler.cpp (+4-4) - (modified) lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp (+2-2) - (modified) lldb/tools/lldb-dap/LLDBUtils.cpp (+11) - (modified) lldb/tools/lldb-dap/LLDBUtils.h (+10-1) ``````````diff diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index b593353110787..4cb0d8e49004c 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -820,12 +820,12 @@ llvm::Error DAP::Disconnect(bool terminateDebuggee) { case lldb::eStateCrashed: case lldb::eStateSuspended: case lldb::eStateStopped: - case lldb::eStateRunning: - debugger.SetAsync(false); + case lldb::eStateRunning: { + ScopeSyncMode scope_sync_mode(debugger); error = terminateDebuggee ? process.Kill() : process.Detach(); - debugger.SetAsync(true); break; } + } SendTerminatedEvent(); diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 3ef87cbef873c..7084d30f2625b 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -9,6 +9,7 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "RequestHandler.h" #include "lldb/API/SBListener.h" #include "llvm/Support/FileSystem.h" @@ -138,9 +139,11 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { } if (attachCommands.empty()) { // No "attachCommands", just attach normally. + // Disable async events so the attach will be successful when we return from // the launch call and the launch will happen synchronously - dap.debugger.SetAsync(false); + ScopeSyncMode scope_sync_mode(dap.debugger); + if (core_file.empty()) { if ((pid != LLDB_INVALID_PROCESS_ID) && (gdb_remote_port != invalid_port)) { @@ -161,10 +164,9 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { // Attach by process name or id. dap.target.Attach(attach_info, error); } - } else + } else { dap.target.LoadCore(core_file.data(), error); - // Reenable async events - dap.debugger.SetAsync(true); + } } else { // We have "attachCommands" that are a set of commands that are expected // to execute the commands after which a process should be created. If there diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index b7d3c8ced69f1..7a75cd93abc19 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -10,6 +10,7 @@ #include "DAP.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolBase.h" #include "Protocol/ProtocolRequests.h" #include "RunInTerminal.h" @@ -138,7 +139,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { else return pid.takeError(); - dap.debugger.SetAsync(false); + std::optional<ScopeSyncMode> scope_sync_mode(dap.debugger); lldb::SBError error; dap.target.Attach(attach_info, error); @@ -162,7 +163,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { // Now that the actual target is just starting (i.e. exec was just invoked), // we return the debugger to its async state. - dap.debugger.SetAsync(true); + scope_sync_mode.reset(); // If sending the notification failed, the launcher should be dead by now and // the async didAttach notification should have an error message, so we @@ -244,9 +245,8 @@ llvm::Error BaseRequestHandler::LaunchProcess( lldb::SBError error; // Disable async events so the launch will be successful when we return from // the launch call and the launch will happen synchronously - dap.debugger.SetAsync(false); + ScopeSyncMode scope_sync_mode(dap.debugger); dap.target.Launch(launch_info, error); - dap.debugger.SetAsync(true); if (error.Fail()) return llvm::make_error<DAPError>(error.GetCString()); } else { diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp index e6f2d9ec669cb..47fedf9dd779c 100644 --- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp @@ -9,6 +9,7 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "LLDBUtils.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include "llvm/Support/JSON.h" @@ -121,8 +122,8 @@ void RestartRequestHandler::operator()( // Stop the current process if necessary. The logic here is similar to // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that // we don't ask the user for confirmation. - dap.debugger.SetAsync(false); if (process.IsValid()) { + ScopeSyncMode scope_sync_mode(dap.debugger); lldb::StateType state = process.GetState(); if (state != lldb::eStateConnected) { process.Kill(); @@ -131,7 +132,6 @@ void RestartRequestHandler::operator()( // for threads of the process we are terminating. dap.thread_ids.clear(); } - dap.debugger.SetAsync(true); // FIXME: Should we run 'preRunCommands'? // FIXME: Should we add a 'preRestartCommands'? diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 7c71d385e9f7e..957ece482ec1b 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -235,4 +235,15 @@ std::string GetStringValue(const lldb::SBStructuredData &data) { return str; } +ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) + : m_debugger(debugger) { + assert(m_debugger.GetAsync() && "Debugger not in async mode!"); + m_debugger.SetAsync(false); +} + +ScopeSyncMode::~ScopeSyncMode() { + assert(!m_debugger.GetAsync() && "Debugger not in async mode!"); + m_debugger.SetAsync(true); +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index 610ebce83566c..05d987a965888 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -198,6 +198,16 @@ class TelemetryDispatcher { lldb::SBDebugger *debugger; }; +/// RAII utility to put the debugger temporarily into synchronous mode. +class ScopeSyncMode { +public: + ScopeSyncMode(lldb::SBDebugger &debugger); + ~ScopeSyncMode(); + +private: + lldb::SBDebugger &m_debugger; +}; + /// Get the stop-disassembly-display settings /// /// \param[in] debugger @@ -207,7 +217,6 @@ class TelemetryDispatcher { /// The value of the stop-disassembly-display setting lldb::StopDisassemblyType GetStopDisassemblyDisplay(lldb::SBDebugger &debugger); - /// Take ownership of the stored error. llvm::Error ToError(const lldb::SBError &error); `````````` </details> https://github.com/llvm/llvm-project/pull/137900 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits