Fix a memory leak in the debugger session where memory was never released after session due to cyclic references in ModelVariableNode.

Fix an incorrect std::move in `DebuggerClientDap::variables` which could have caused incorrect states.
Fix invalid memory access in `LSPDocumentClient::requestSemanticHighlighting`.
This commit is contained in:
Martín Lucas Golini
2025-08-10 17:34:32 -03:00
parent 4da71def34
commit a1959fd149
7 changed files with 15050 additions and 25 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -848,24 +848,35 @@ bool DebuggerClientDap::variables( int variablesReference, Variable::Type filter
[this, responseCb = std::move( responseCb )]( const Response& response,
const nlohmann::json& request ) {
const int variablesReference = request.value( DAP_VARIABLES_REFERENCE, 0 );
if ( response.success ) {
auto variableList( Variable::parseList( response.body[DAP_VARIABLES] ) );
auto variableList = Variable::parseList( response.body[DAP_VARIABLES] );
if ( responseCb ) {
responseCb( variablesReference, std::move( variableList ) );
} else {
for ( auto listener : mListeners )
listener->variables( variablesReference, std::move( variableList ),
mCurrentSessionId );
} else if ( !mListeners.empty() ) {
if ( mListeners.size() == 1 ) {
// Move directly to single listener
mListeners[0]->variables( variablesReference, std::move( variableList ),
mCurrentSessionId );
} else {
// Copy for multiple listeners
for ( auto listener : mListeners ) {
std::vector<Variable> variableListCopy = variableList;
listener->variables( variablesReference, std::move( variableListCopy ),
mCurrentSessionId );
}
}
}
} else {
std::vector<Variable> variableList;
std::vector<Variable> variableList; // Single empty vector
if ( responseCb ) {
responseCb( variablesReference, std::move( variableList ) );
} else {
for ( auto listener : mListeners )
listener->variables( variablesReference, std::move( variableList ),
} else if ( !mListeners.empty() ) {
// Share empty vector with all listeners
for ( auto listener : mListeners ) {
std::vector<Variable> variableListCopy = variableList;
listener->variables( variablesReference, std::move( variableListCopy ),
mCurrentSessionId );
}
}
}
},

View File

@@ -34,7 +34,7 @@ DebuggerClientListener::DebuggerClientListener( DebuggerClient* client, Debugger
}
DebuggerClientListener::~DebuggerClientListener() {
resetState();
resetState( true );
auto sdc = getStatusDebuggerController();
if ( !mPlugin->isShuttingDown() && sdc ) {
if ( sdc->getUIThreads() )
@@ -243,7 +243,7 @@ void DebuggerClientListener::configured( const SessionId& ) {}
void DebuggerClientListener::failed( const SessionId& ) {
mPlugin->exitDebugger();
resetState();
resetState( true );
}
void DebuggerClientListener::debuggeeRunning( const SessionId& ) {}
@@ -251,13 +251,13 @@ void DebuggerClientListener::debuggeeRunning( const SessionId& ) {}
void DebuggerClientListener::debuggeeTerminated( const SessionId& ) {
if ( mClient->sessionsActive() == 0 ) {
mPlugin->exitDebugger();
resetState();
resetState( true );
}
}
void DebuggerClientListener::capabilitiesReceived( const Capabilities& /*capabilities*/ ) {}
void DebuggerClientListener::resetState() {
void DebuggerClientListener::resetState( bool full ) {
mStoppedData = {};
mCurrentScopePos = {};
mCurrentFrameId = 0;
@@ -265,12 +265,13 @@ void DebuggerClientListener::resetState() {
mThreadsModel->resetThreads();
if ( mStackModel )
mStackModel->resetStack();
mVariablesHolder->clear();
mVariablesHolder->clear( full );
mScopeRef.clear();
}
void DebuggerClientListener::debuggeeExited( int /*exitCode*/, const SessionId& ) {
mPlugin->exitDebugger();
resetState();
resetState( true );
}
void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event, const SessionId& ) {
@@ -320,7 +321,7 @@ void DebuggerClientListener::debuggeeStopped( const StoppedEvent& event, const S
}
void DebuggerClientListener::debuggeeContinued( const ContinuedEvent&, const SessionId& ) {
resetState();
resetState( false );
UISceneNode* sceneNode = mPlugin->getUISceneNode();
sceneNode->runOnMainThread( [sceneNode] { sceneNode->getRoot()->invalidateDraw(); } );

View File

@@ -133,7 +133,7 @@ class DebuggerClientListener : public DebuggerClient::Listener {
StatusDebuggerController* getStatusDebuggerController() const;
void resetState();
void resetState( bool full );
void changeScope( const StackFrame& f );

View File

@@ -47,7 +47,7 @@ void ModelVariableNode::addChild( NodePtr child ) {
}
ModelVariableNode::NodePtr ModelVariableNode::getParent() const {
return parent;
return parent.lock();
}
std::optional<ModelVariableNode::NodePtr> ModelVariableNode::getChild( int variablesReference ) {
@@ -166,6 +166,10 @@ VariablesHolder::VariablesHolder( UISceneNode* sceneNode ) :
mNodeMap[0] = mRootNode;
}
VariablesHolder::~VariablesHolder() {
clear( true );
}
void VariablesHolder::addVariables( const int variablesReference, std::vector<Variable>&& vars ) {
Lock l( mMutex );
auto parentNode = getNodeByReference( variablesReference );
@@ -244,6 +248,7 @@ void VariablesHolder::clear( bool all ) {
if ( all ) {
mNodeMap.clear();
mCurrentLocation = {};
mExpandedStates.clear();
}
}
@@ -256,7 +261,8 @@ VariablePath VariablesHolder::buildVariablePath( ModelVariableNode* node ) const
VariablePath path;
while ( node && node != mRootNode.get() ) {
path.push_back( node->getName() );
node = node->parent ? node->parent.get() : nullptr;
auto parentNode = node->parent.lock();
node = parentNode.get();
}
std::reverse( path.begin(), path.end() );
return path;

View File

@@ -68,6 +68,7 @@ namespace ecode {
struct ModelVariableNode : public std::enable_shared_from_this<ModelVariableNode> {
using NodePtr = std::shared_ptr<ModelVariableNode>;
using WeakNodePtr = std::weak_ptr<ModelVariableNode>;
ModelVariableNode( Variable&& var, NodePtr parent );
@@ -93,7 +94,7 @@ struct ModelVariableNode : public std::enable_shared_from_this<ModelVariableNode
NodePtr getParent() const;
NodePtr parent{ nullptr };
WeakNodePtr parent;
Variable var;
std::vector<NodePtr> children;
};
@@ -127,6 +128,8 @@ class VariablesHolder {
public:
VariablesHolder( UISceneNode* sceneNode );
~VariablesHolder();
void addVariables( const int variablesReference, std::vector<Variable>&& vars );
void addChild( ModelVariableNode::NodePtr child );

View File

@@ -175,9 +175,9 @@ void LSPDocumentClient::requestSemanticHighlighting( bool reqFull ) {
Uint64 docModId = mDoc->getModificationId();
mServer->documentSemanticTokensFull(
mDoc->getURI(), delta, reqId, range,
[docClient, uri, server, docModId, this]( const auto&, LSPSemanticTokensDelta&& deltas ) {
BoolScopedOp op( mProcessingSemanticTokensResponse, true );
[docClient, uri, server, docModId]( const auto&, LSPSemanticTokensDelta&& deltas ) {
if ( server->hasDocumentClient( docClient ) && server->hasDocument( uri ) ) {
BoolScopedOp op( docClient->mProcessingSemanticTokensResponse, true );
docClient->mWaitingSemanticTokensResponse = false;
docClient->processTokens( std::move( deltas ), docModId );
}