forked from qt-creator/qt-creator
Debugger: Fix object leakage on shutdown and heap-use-after-free.
Task-number: QTCREATORBUG-15938 Change-Id: I437756705c33730398a129651fabe34c92334656 Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
This commit is contained in:
@@ -81,9 +81,22 @@ DebuggerMainWindow::~DebuggerMainWindow()
|
|||||||
{
|
{
|
||||||
// as we have to setParent(0) on dock widget that are not selected,
|
// as we have to setParent(0) on dock widget that are not selected,
|
||||||
// we keep track of all and make sure we don't leak any
|
// we keep track of all and make sure we don't leak any
|
||||||
foreach (const DockPtr &ptr, m_dockWidgets) {
|
foreach (const Perspective &perspective, m_perspectiveForPerspectiveId) {
|
||||||
if (ptr)
|
foreach (const Perspective::Operation &operation, perspective.operations()) {
|
||||||
delete ptr.data();
|
if (operation.widget) {
|
||||||
|
// There are two possible states: Either addDockForWidget(widget) has
|
||||||
|
// been on operation.widget (e.g. when the perspective gets activated)
|
||||||
|
// for the first time, or not. In the first case we delete only the
|
||||||
|
// widget, in the second case its parent, which is the dock.
|
||||||
|
if (QWidget *parent = operation.widget->parentWidget()) {
|
||||||
|
QTC_CHECK(qobject_cast<QDockWidget *>(parent));
|
||||||
|
delete parent;
|
||||||
|
} else {
|
||||||
|
// These are from perspectives that never
|
||||||
|
delete operation.widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,11 +132,6 @@ QDockWidget *DebuggerMainWindow::dockWidget(const QByteArray &dockId) const
|
|||||||
return m_dockForDockId.value(dockId);
|
return m_dockForDockId.value(dockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *DebuggerMainWindow::modeWindow()
|
|
||||||
{
|
|
||||||
return m_modeWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DebuggerMainWindow::resetCurrentPerspective()
|
void DebuggerMainWindow::resetCurrentPerspective()
|
||||||
{
|
{
|
||||||
loadPerspectiveHelper(m_currentPerspectiveId, false);
|
loadPerspectiveHelper(m_currentPerspectiveId, false);
|
||||||
@@ -140,7 +148,7 @@ void DebuggerMainWindow::restorePerspective(const QByteArray &perspectiveId)
|
|||||||
m_perspectiveChooser->setCurrentIndex(index);
|
m_perspectiveChooser->setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerMainWindow::finalizeSetup(Core::IMode *mode, QWidget *central)
|
void DebuggerMainWindow::finalizeSetup()
|
||||||
{
|
{
|
||||||
auto viewButton = new QToolButton;
|
auto viewButton = new QToolButton;
|
||||||
viewButton->setText(tr("Views"));
|
viewButton->setText(tr("Views"));
|
||||||
@@ -195,7 +203,10 @@ void DebuggerMainWindow::finalizeSetup(Core::IMode *mode, QWidget *central)
|
|||||||
m_toolbarDock = dock;
|
m_toolbarDock = dock;
|
||||||
|
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, dock);
|
addDockWidget(Qt::BottomDockWidgetArea, dock);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *createModeWindow(Core::IMode *mode, DebuggerMainWindow *mainWindow, QWidget *central)
|
||||||
|
{
|
||||||
if (!central)
|
if (!central)
|
||||||
central = new EditorManagerPlaceHolder(mode);
|
central = new EditorManagerPlaceHolder(mode);
|
||||||
|
|
||||||
@@ -225,7 +236,7 @@ void DebuggerMainWindow::finalizeSetup(Core::IMode *mode, QWidget *central)
|
|||||||
|
|
||||||
// Right-side window with editor, output etc.
|
// Right-side window with editor, output etc.
|
||||||
auto mainWindowSplitter = new MiniSplitter;
|
auto mainWindowSplitter = new MiniSplitter;
|
||||||
mainWindowSplitter->addWidget(this);
|
mainWindowSplitter->addWidget(mainWindow);
|
||||||
mainWindowSplitter->addWidget(new OutputPanePlaceHolder(mode, mainWindowSplitter));
|
mainWindowSplitter->addWidget(new OutputPanePlaceHolder(mode, mainWindowSplitter));
|
||||||
auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter);
|
auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter);
|
||||||
outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder"));
|
outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder"));
|
||||||
@@ -242,9 +253,9 @@ void DebuggerMainWindow::finalizeSetup(Core::IMode *mode, QWidget *central)
|
|||||||
splitter->setStretchFactor(0, 0);
|
splitter->setStretchFactor(0, 0);
|
||||||
splitter->setStretchFactor(1, 1);
|
splitter->setStretchFactor(1, 1);
|
||||||
splitter->setObjectName(QLatin1String("DebugModeWidget"));
|
splitter->setObjectName(QLatin1String("DebugModeWidget"));
|
||||||
setCentralWidget(centralEditorWidget);
|
mainWindow->setCentralWidget(centralEditorWidget);
|
||||||
|
|
||||||
m_modeWindow = splitter;
|
return splitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings)
|
void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings)
|
||||||
@@ -351,7 +362,6 @@ QDockWidget *DebuggerMainWindow::registerDockWidget(const QByteArray &dockId, QW
|
|||||||
QTC_ASSERT(!widget->objectName().isEmpty(), return 0);
|
QTC_ASSERT(!widget->objectName().isEmpty(), return 0);
|
||||||
QDockWidget *dockWidget = addDockForWidget(widget);
|
QDockWidget *dockWidget = addDockForWidget(widget);
|
||||||
dockWidget->setParent(0);
|
dockWidget->setParent(0);
|
||||||
m_dockWidgets.append(DebuggerMainWindow::DockPtr(dockWidget));
|
|
||||||
m_dockForDockId[dockId] = dockWidget;
|
m_dockForDockId[dockId] = dockWidget;
|
||||||
return dockWidget;
|
return dockWidget;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
Qt::DockWidgetArea area = Qt::BottomDockWidgetArea);
|
Qt::DockWidgetArea area = Qt::BottomDockWidgetArea);
|
||||||
|
|
||||||
QByteArray dockId;
|
QByteArray dockId;
|
||||||
QWidget *widget = 0;
|
QPointer<QWidget> widget;
|
||||||
QByteArray anchorDockId;
|
QByteArray anchorDockId;
|
||||||
OperationType operationType;
|
OperationType operationType;
|
||||||
bool visibleByDefault;
|
bool visibleByDefault;
|
||||||
@@ -115,14 +115,12 @@ public:
|
|||||||
void resetCurrentPerspective();
|
void resetCurrentPerspective();
|
||||||
void restorePerspective(const QByteArray &perspectiveId);
|
void restorePerspective(const QByteArray &perspectiveId);
|
||||||
|
|
||||||
void finalizeSetup(Core::IMode *mode, QWidget *central = 0);
|
void finalizeSetup();
|
||||||
|
|
||||||
void showStatusMessage(const QString &message, int timeoutMS);
|
void showStatusMessage(const QString &message, int timeoutMS);
|
||||||
QDockWidget *dockWidget(const QByteArray &dockId) const;
|
QDockWidget *dockWidget(const QByteArray &dockId) const;
|
||||||
QByteArray currentPerspective() const { return m_currentPerspectiveId; }
|
QByteArray currentPerspective() const { return m_currentPerspectiveId; }
|
||||||
|
|
||||||
QWidget *modeWindow();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDockWidget *registerDockWidget(const QByteArray &dockId, QWidget *widget);
|
QDockWidget *registerDockWidget(const QByteArray &dockId, QWidget *widget);
|
||||||
void loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings = true);
|
void loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings = true);
|
||||||
@@ -136,14 +134,10 @@ private:
|
|||||||
QHash<QByteArray, QDockWidget *> m_dockForDockId;
|
QHash<QByteArray, QDockWidget *> m_dockForDockId;
|
||||||
QHash<QByteArray, QWidget *> m_toolbarForPerspectiveId;
|
QHash<QByteArray, QWidget *> m_toolbarForPerspectiveId;
|
||||||
QHash<QByteArray, Perspective> m_perspectiveForPerspectiveId;
|
QHash<QByteArray, Perspective> m_perspectiveForPerspectiveId;
|
||||||
|
|
||||||
// list of dock widgets to prevent memory leak
|
|
||||||
typedef QPointer<QDockWidget> DockPtr;
|
|
||||||
QList<DockPtr> m_dockWidgets;
|
|
||||||
|
|
||||||
QWidget *m_modeWindow = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QWidget *createModeWindow(Core::IMode *mode, DebuggerMainWindow *mainWindow, QWidget *central);
|
||||||
|
|
||||||
} // Utils
|
} // Utils
|
||||||
|
|
||||||
#endif // DEBUGGERMAINWINDOW_H
|
#endif // DEBUGGERMAINWINDOW_H
|
||||||
|
|||||||
@@ -486,41 +486,27 @@ bool DummyEngine::hasCapability(unsigned cap) const
|
|||||||
class DebugModeContext : public IContext
|
class DebugModeContext : public IContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebugModeContext(DebuggerMainWindow *mainWindow) : m_mainWindow(mainWindow)
|
DebugModeContext(QWidget *modeWindow)
|
||||||
{
|
{
|
||||||
setContext(Context(CC::C_EDITORMANAGER));
|
setContext(Context(CC::C_EDITORMANAGER));
|
||||||
|
setWidget(modeWindow);
|
||||||
ICore::addContextObject(this);
|
ICore::addContextObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *widget() const override { return m_mainWindow->modeWindow(); }
|
|
||||||
|
|
||||||
DebuggerMainWindow *m_mainWindow;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DebugMode : public IMode
|
class DebugMode : public IMode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DebugMode(DebuggerMainWindow *mainWindow) : m_mainWindow(mainWindow)
|
DebugMode()
|
||||||
{
|
{
|
||||||
setObjectName(QLatin1String("DebugMode"));
|
setObjectName(QLatin1String("DebugMode"));
|
||||||
setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
|
setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE));
|
||||||
setDisplayName(DebuggerPlugin::tr("Debug"));
|
setDisplayName(DebuggerPlugin::tr("Debug"));
|
||||||
setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC,
|
setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC,
|
||||||
Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE));
|
Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE));
|
||||||
// setIcon(Utils::Icon::modeIcon(Icons::MODE_ANALYZE_CLASSIC,
|
|
||||||
// Icons::MODE_ANALYZE_FLAT, Icons::MODE_ANALYZE_FLAT_ACTIVE));
|
|
||||||
setPriority(85);
|
setPriority(85);
|
||||||
setId(MODE_DEBUG);
|
setId(MODE_DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *widget() const override { return m_mainWindow->modeWindow(); }
|
|
||||||
|
|
||||||
~DebugMode()
|
|
||||||
{
|
|
||||||
// delete m_widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebuggerMainWindow *m_mainWindow;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
@@ -924,7 +910,9 @@ public:
|
|||||||
void updateActiveLanguages();
|
void updateActiveLanguages();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DebuggerMainWindow *m_mainWindow = 0;
|
QPointer<DebuggerMainWindow> m_mainWindow;
|
||||||
|
QPointer<QWidget> m_modeWindow;
|
||||||
|
QPointer<DebugMode> m_mode;
|
||||||
|
|
||||||
QHash<Id, ActionDescription> m_descriptions;
|
QHash<Id, ActionDescription> m_descriptions;
|
||||||
ActionContainer *m_menu = 0;
|
ActionContainer *m_menu = 0;
|
||||||
@@ -1051,11 +1039,6 @@ DebuggerPluginPrivate::~DebuggerPluginPrivate()
|
|||||||
|
|
||||||
delete m_breakHandler;
|
delete m_breakHandler;
|
||||||
m_breakHandler = 0;
|
m_breakHandler = 0;
|
||||||
|
|
||||||
// delete m_debugMode;
|
|
||||||
// m_debugMode = 0;
|
|
||||||
delete m_mainWindow;
|
|
||||||
m_mainWindow = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DebuggerEngine *DebuggerPluginPrivate::dummyEngine()
|
DebuggerEngine *DebuggerPluginPrivate::dummyEngine()
|
||||||
@@ -1748,13 +1731,16 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments,
|
|||||||
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
|
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
|
||||||
this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu);
|
this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu);
|
||||||
|
|
||||||
|
m_mainWindow->finalizeSetup();
|
||||||
|
|
||||||
// Debug mode setup
|
// Debug mode setup
|
||||||
auto mode = new DebugMode(m_mainWindow);
|
m_mode = new DebugMode;
|
||||||
|
m_modeWindow = createModeWindow(m_mode, m_mainWindow, 0);
|
||||||
|
m_mode->setWidget(m_modeWindow);
|
||||||
|
|
||||||
(void) new DebugModeContext(m_mainWindow);
|
(void) new DebugModeContext(m_mainWindow);
|
||||||
m_mainWindow->finalizeSetup(mode);
|
|
||||||
|
|
||||||
m_plugin->addAutoReleasedObject(mode);
|
m_plugin->addObject(m_mode);
|
||||||
|
|
||||||
|
|
||||||
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
|
connect(SessionManager::instance(), &SessionManager::startupProjectChanged,
|
||||||
@@ -3047,6 +3033,23 @@ void DebuggerPluginPrivate::aboutToShutdown()
|
|||||||
disconnect(SessionManager::instance(),
|
disconnect(SessionManager::instance(),
|
||||||
SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
|
SIGNAL(startupProjectChanged(ProjectExplorer::Project*)),
|
||||||
this, 0);
|
this, 0);
|
||||||
|
|
||||||
|
m_mainWindow->saveCurrentPerspective();
|
||||||
|
delete m_mainWindow;
|
||||||
|
m_mainWindow = 0;
|
||||||
|
|
||||||
|
// removeObject leads to aboutToRemoveObject, which leads to
|
||||||
|
// ModeManager::aboutToRemove, which leads to the mode manager
|
||||||
|
// removing the mode's widget from the stackwidget
|
||||||
|
// (currently by index, but possibly the stackwidget resets the
|
||||||
|
// parent and stuff on the widget)
|
||||||
|
m_plugin->removeObject(m_mode);
|
||||||
|
|
||||||
|
delete m_modeWindow;
|
||||||
|
m_modeWindow = 0;
|
||||||
|
|
||||||
|
delete m_mode;
|
||||||
|
m_mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState(DebuggerEngine *engine)
|
void updateState(DebuggerEngine *engine)
|
||||||
@@ -3214,7 +3217,6 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown()
|
|||||||
{
|
{
|
||||||
removeObject(this);
|
removeObject(this);
|
||||||
dd->aboutToShutdown();
|
dd->aboutToShutdown();
|
||||||
dd->m_mainWindow->saveCurrentPerspective();
|
|
||||||
return SynchronousShutdown;
|
return SynchronousShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -503,7 +503,6 @@ CallgrindTool::CallgrindTool(QObject *parent)
|
|||||||
CallgrindTool::~CallgrindTool()
|
CallgrindTool::~CallgrindTool()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_textMarks);
|
qDeleteAll(m_textMarks);
|
||||||
doClear(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallgrindTool::slotGoToOverview()
|
void CallgrindTool::slotGoToOverview()
|
||||||
|
|||||||
Reference in New Issue
Block a user