From 65a3e484a905bf3fbac86784dd20ec421fbb401d Mon Sep 17 00:00:00 2001 From: Andrii Semkiv Date: Wed, 4 Dec 2024 15:26:07 +0100 Subject: [PATCH] Debugger: Add an option to control heap debugging Added a checkbox (temporarily) in CDB settings page that toggles the heap debugging on Windows. Although it is "technically" a CDB option, it woks with LLDB on Windows as well. The default behavior is to keep the heap debugging off. The checkbox can still be overridden by the environment variable. Fixes: QTCREATORBUG-32102 Change-Id: I580cd0d66da38776f3a51632ede6b5f60d4d4cfd Reviewed-by: hjk Reviewed-by: David Schulz --- src/plugins/debugger/cdb/cdbengine.cpp | 4 ++++ src/plugins/debugger/cdb/cdboptionspage.cpp | 5 +++- src/plugins/debugger/debuggeractions.cpp | 9 ++++++++ src/plugins/debugger/debuggeractions.h | 1 + .../debugger/debuggerinternalconstants.h | 2 ++ src/plugins/debugger/lldb/lldbengine.cpp | 23 +++++++++++++------ 6 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 16aab0c920c..0dc2d321613 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -406,6 +406,10 @@ void CdbEngine::setupEngine() if (!oldCdbExtensionPath.isEmpty()) inferiorEnvironment.appendOrSet(cdbExtensionPathVariableC, oldCdbExtensionPath); + if (!inferiorEnvironment.hasKey(Debugger::Constants::NO_DEBUG_HEAP)) { + const QString value = s.enableHeapDebugging() ? "0" : "1"; + inferiorEnvironment.set(Debugger::Constants::NO_DEBUG_HEAP, value); + } m_process.setEnvironment(inferiorEnvironment); if (!sp.inferior.workingDirectory.isEmpty()) m_process.setWorkingDirectory(sp.inferior.workingDirectory); diff --git a/src/plugins/debugger/cdb/cdboptionspage.cpp b/src/plugins/debugger/cdb/cdboptionspage.cpp index ef3586e61b6..1cf5a2a2855 100644 --- a/src/plugins/debugger/cdb/cdboptionspage.cpp +++ b/src/plugins/debugger/cdb/cdboptionspage.cpp @@ -171,6 +171,7 @@ CdbOptionsPageWidget::CdbOptionsPageWidget() m_breakEventWidget->setBreakEvents(settings().cdbBreakEvents()); + // clang-format off Column { Row { Group { @@ -188,7 +189,8 @@ CdbOptionsPageWidget::CdbOptionsPageWidget() s.ignoreFirstChanceAccessViolation, s.cdbBreakOnCrtDbgReport, s.cdbBreakPointCorrection, - s.cdbUsePythonDumper + s.cdbUsePythonDumper, + s.enableHeapDebugging } } }, @@ -209,6 +211,7 @@ CdbOptionsPageWidget::CdbOptionsPageWidget() st }.attachTo(this); + // clang-format on } void CdbOptionsPageWidget::apply() diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 20ff6cddefd..1033524538a 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -190,6 +190,14 @@ DebuggerSettings::DebuggerSettings() : ignoreFirstChanceAccessViolation.setSettingsKey(cdbSettingsGroup, "IgnoreFirstChanceAccessViolation"); ignoreFirstChanceAccessViolation.setLabelText(Tr::tr("Ignore first chance access violations")); + enableHeapDebugging.setSettingsKey(cdbSettingsGroup, "EnableHeapDebugging"); + enableHeapDebugging.setLabelText(Tr::tr("Enable heap debugging")); + enableHeapDebugging.setToolTip( + "

" + + Tr::tr("Allocate memory using the debug heap rather than the normal heap. The debug heap " + "enables additional checks to help diagnose heap related bugs. However it comes " + "at a performance cost when allocating memory in the debugged process")); + // // Locals & Watchers sortStructMembers.setSettingsKey(debugModeGroup, "SortStructMembers"); @@ -255,6 +263,7 @@ DebuggerSettings::DebuggerSettings() : page5.registerAspect(&firstChanceExceptionTaskEntry); page5.registerAspect(&secondChanceExceptionTaskEntry); page5.registerAspect(&ignoreFirstChanceAccessViolation); + page5.registerAspect(&enableHeapDebugging); // Page 6 page6.registerAspect(&cdbSymbolPaths); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 2134c5d03a4..e5d1ae0fa29 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -89,6 +89,7 @@ public: Utils::BoolAspect firstChanceExceptionTaskEntry; Utils::BoolAspect secondChanceExceptionTaskEntry; Utils::BoolAspect ignoreFirstChanceAccessViolation; + Utils::BoolAspect enableHeapDebugging; // Page 6: CDB Paths Utils::StringListAspect cdbSymbolPaths; diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index c1cef9f7f7f..26c703ddcf4 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -53,6 +53,8 @@ const char DISASSEMBLER_SOURCE_FILE[] = "DisassemblerSourceFile"; const char CRT_DEBUG_REPORT[] = "CrtDbgReport"; +const char NO_DEBUG_HEAP[] = "_NO_DEBUG_HEAP"; + } // namespace Constants enum ModelRoles diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 65b45cbda61..93e82be4c0d 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -264,22 +264,31 @@ void LldbEngine::handleLldbStarted() for (const FilePath &path : rp.solibSearchPath) executeDebuggerCommand("settings append target.exec-search-paths " + path.toString()); + const ProcessRunData &inferior = rp.inferior; + const FilePath &executable = inferior.command.executable(); DebuggerCommand cmd2("setupInferior"); - cmd2.arg("executable", rp.inferior.command.executable().path()); + cmd2.arg("executable", executable.path()); cmd2.arg("breakonmain", rp.breakOnMain); cmd2.arg("useterminal", usesTerminal()); cmd2.arg("startmode", rp.startMode); cmd2.arg("nativemixed", isNativeMixedActive()); - cmd2.arg("workingdirectory", rp.inferior.workingDirectory.path()); - QStringList environment = rp.inferior.environment.toStringList(); + cmd2.arg("workingdirectory", inferior.workingDirectory.path()); + Environment environment = inferior.environment; // Prevent lldb from automatically setting OS_ACTIVITY_DT_MODE to mirror // NSLog to stderr, as that will also mirror os_log, which we pick up in // AppleUnifiedLogger::preventsStderrLogging(), and end up disabling Qt's // default stderr logger. We prefer Qt's own stderr logging if we can. - environment << "IDE_DISABLED_OS_ACTIVITY_DT_MODE=1"; - cmd2.arg("environment", environment); - cmd2.arg("processargs", toHex(ProcessArgs::splitArgs(rp.inferior.command.arguments(), - HostOsInfo::hostOs()).join(QChar(0)))); + environment.set("IDE_DISABLED_OS_ACTIVITY_DT_MODE", "1"); + if (executable.osType() == Utils::OsTypeWindows + && !environment.hasKey(Debugger::Constants::NO_DEBUG_HEAP)) { + const QString value = settings().enableHeapDebugging() ? "0" : "1"; + environment.set(Debugger::Constants::NO_DEBUG_HEAP, value); + } + cmd2.arg("environment", environment.toStringList()); + cmd2.arg( + "processargs", + toHex(ProcessArgs::splitArgs(inferior.command.arguments(), HostOsInfo::hostOs()) + .join(QChar(0)))); cmd2.arg("platform", rp.platform); cmd2.arg("symbolfile", rp.symbolFile.path());