From 11be1bb1e712a7f5281589e40d1844946e208055 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Sat, 1 Aug 2026 16:44:34 -0400 Subject: [PATCH 1/2] deviceapi: Avoid invalid iterator erase in removeBuddy In std::vector::erase, The iterator pos must be valid and dereferenceable. Thus the end() iterator (which is valid, but is not dereferenceable) cannot be used as a value for pos. Protect against that by checking the result of std::find() before erasing a buddy entry. The buddy should always be present when removeBuddy() is called, but avoid undefined behavior if that assumption is violated. Signed-off-by: Robin Getz --- sdrbase/device/deviceapi.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index 9e08b0723..d969272ba 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -774,13 +774,25 @@ void DeviceAPI::removeBuddy(DeviceAPI* buddy) { switch(buddy->m_streamType) { case StreamSingleRx: - m_sourceBuddies.erase(std::find(m_sourceBuddies.begin(), m_sourceBuddies.end(), buddy)); + { + auto it = std::find(m_sourceBuddies.begin(), m_sourceBuddies.end(), buddy); + if (it != m_sourceBuddies.end()) + { + m_sourceBuddies.erase(it); + } break; + } case StreamSingleTx: - m_sinkBuddies.erase(std::find(m_sinkBuddies.begin(), m_sinkBuddies.end(), buddy)); + { + auto it = std::find(m_sinkBuddies.begin(), m_sinkBuddies.end(), buddy); + if (it != m_sinkBuddies.end()) + { + m_sinkBuddies.erase(it); + } break; + } default: - qDebug("DeviceAPI::removeSourceBuddy: buddy %s(%s) is not of single Rx or Tx type", + qDebug("DeviceAPI::removeBuddy: buddy %s(%s) is not of single Rx or Tx type", qPrintable(buddy->getHardwareId()), qPrintable(buddy->getSamplingDeviceSerial())); return; From 0928de3b7becb2c03c3e57464a33ab640efbc7fe Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Sat, 1 Aug 2026 17:06:39 -0400 Subject: [PATCH 2/2] deviceapi: Avoid iterator invalidation when clearing buddy lists Fix cppcheck warning: Using iterator to member container 'm_sinkBuddies' that may be invalid clearBuddiesLists() was iterating directly over m_sourceBuddies and m_sinkBuddies while calling removeBuddy(), which modifies the buddy relationship lists. This could invalidate the active iterator and result in undefined behavior. The issue could lead to intermittent failures during buddy cleanup operations, such as device removal, device reload, or application shutdown, depending on container state and timing. Iterate over copies of the buddy lists so that removing relationships does not affect the iterators used for traversal. Signed-off-by: Robin Getz --- sdrbase/device/deviceapi.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index d969272ba..9f6cd2921 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -801,32 +801,35 @@ void DeviceAPI::removeBuddy(DeviceAPI* buddy) void DeviceAPI::clearBuddiesLists() { - auto itSource = m_sourceBuddies.begin(); - auto itSink = m_sinkBuddies.begin(); + // Make copies before iterating because removeBuddy() modifies the buddy + // relationship lists. Iterating directly over m_sourceBuddies/m_sinkBuddies + // could invalidate iterators while the relationships are being removed. + auto sourceCopy = m_sourceBuddies; + auto sinkCopy = m_sinkBuddies; bool leaderElected = false; - for (;itSource != m_sourceBuddies.end(); ++itSource) + for (auto* buddy : sourceCopy) { if (isBuddyLeader() && !leaderElected) { - (*itSource)->setBuddyLeader(true); + buddy->setBuddyLeader(true); leaderElected = true; } - (*itSource)->removeBuddy(this); + buddy->removeBuddy(this); } m_sourceBuddies.clear(); - for (;itSink != m_sinkBuddies.end(); ++itSink) + for (auto* buddy : sinkCopy) { if (isBuddyLeader() && !leaderElected) { - (*itSink)->setBuddyLeader(true); + buddy->setBuddyLeader(true); leaderElected = true; } - (*itSink)->removeBuddy(this); + buddy->removeBuddy(this); } m_sinkBuddies.clear();