diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index e819d15b291..d4241160db6 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -227,6 +227,7 @@ class DumperBase(): self.watchers = args.get('watchers', {}) self.useDynamicType = int(args.get('dyntype', '0')) self.useFancy = int(args.get('fancy', '0')) + self.allowInferiorCalls = int(args.get('allowinferiorcalls', '0')) self.forceQtNamespace = int(args.get('forcens', '0')) self.passExceptions = int(args.get('passexceptions', '0')) self.isTesting = int(args.get('testing', '0')) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index ee25520bced..e1a6ae64d63 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -739,6 +739,9 @@ class Dumper(DumperBase): def nativeParseAndEvaluate(self, exp): #self.warn('EVALUATE "%s"' % exp) try: + if not self.allowInferiorCalls: + return None + val = gdb.parse_and_eval(exp) return val except RuntimeError as error: @@ -772,6 +775,9 @@ class Dumper(DumperBase): #self.warn('PTR: %s -> %s(%s)' % (value, function, addr)) exp = '((%s*)0x%x)->%s(%s)' % (type_name, addr, function, arg) #self.warn('CALL: %s' % exp) + if not self.allowInferiorCalls: + return None + result = gdb.parse_and_eval(exp) #self.warn(' -> %s' % result) res = self.fromNativeValue(result) @@ -1504,6 +1510,12 @@ class CliDumper(Dumper): args = {} args['fancy'] = 1 + # It enables skipping the execution of gdb.parse_and_eval which prevents the application from being rerun, + # which could lead to hitting breakpoints repeatedly in different threads, causing an infinite loop. + # Currently, gdb.parse_and_eval is bypassed in several places, resolving the bug QTCREATORBUG-23219. + # In the future, a full wrapper for gdb.parse_and_eval might be necessary to avoid this issue entirely. + # For now, we leave it as-is to retain as much pretty-printing functionality as possible. + args['allowinferiorcalls'] = 1 args['passexceptions'] = 1 args['autoderef'] = 1 args['qobjectnames'] = 1 diff --git a/src/plugins/debugger/commonoptionspage.cpp b/src/plugins/debugger/commonoptionspage.cpp index 4c270d72d65..8e6a162074f 100644 --- a/src/plugins/debugger/commonoptionspage.cpp +++ b/src/plugins/debugger/commonoptionspage.cpp @@ -235,6 +235,10 @@ LocalsAndExpressionsSettings::LocalsAndExpressionsSettings() useDebuggingHelpers.setDefaultValue(true); useDebuggingHelpers.setLabelText(Tr::tr("Use Debugging Helpers")); + allowInferiorCalls.setSettingsKey(debugModeGroup, "AllowInferiorCalls"); + allowInferiorCalls.setDefaultValue(true); + allowInferiorCalls.setLabelText(Tr::tr("Allow inferior calls in debugging helper")); + useCodeModel.setSettingsKey(debugModeGroup, "UseCodeModel"); useCodeModel.setDefaultValue(true); useCodeModel.setLabelText(Tr::tr("Use code model")); @@ -354,6 +358,7 @@ LocalsAndExpressionsSettings::LocalsAndExpressionsSettings() return Column { useDebuggingHelpers, + allowInferiorCalls, useHelper, Space(10), showStdNamespace, diff --git a/src/plugins/debugger/commonoptionspage.h b/src/plugins/debugger/commonoptionspage.h index d8ba963cd12..c2493289ee0 100644 --- a/src/plugins/debugger/commonoptionspage.h +++ b/src/plugins/debugger/commonoptionspage.h @@ -76,6 +76,7 @@ public: LocalsAndExpressionsSettings(); Utils::BoolAspect useDebuggingHelpers{this}; + Utils::BoolAspect allowInferiorCalls{this}; Utils::BoolAspect useCodeModel{this}; Utils::BoolAspect showThreadNames{this}; Utils::FilePathAspect extraDumperFile{this}; // For loading a file. Recommended. diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 0bf63efca26..20ff6cddefd 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -76,6 +76,7 @@ DebuggerSettings::DebuggerSettings() : // Page 4 useDebuggingHelpers{localsAndExpressionSettings().useDebuggingHelpers}, + allowInferiorCalls{localsAndExpressionSettings().allowInferiorCalls}, useCodeModel{localsAndExpressionSettings().useCodeModel}, showThreadNames{localsAndExpressionSettings().showThreadNames}, extraDumperFile{localsAndExpressionSettings().extraDumperFile}, // For loading a file. Recommended. diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index c0eff56d090..2134c5d03a4 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -65,6 +65,7 @@ public: // Page 4: Locals and expressions Utils::BoolAspect &useDebuggingHelpers; + Utils::BoolAspect &allowInferiorCalls; Utils::BoolAspect &useCodeModel; Utils::BoolAspect &showThreadNames; Utils::FilePathAspect &extraDumperFile; // For loading a file. Recommended. diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index d1e65f3ed18..fa8646d73e0 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -145,6 +145,8 @@ GdbEngine::GdbEngine() this, &GdbEngine::createFullBacktrace); connect(&s.useDebuggingHelpers, &BaseAspect::changed, this, &GdbEngine::reloadLocals); + connect(&s.allowInferiorCalls, &BaseAspect::changed, + this, &GdbEngine::reloadLocals); connect(&s.useDynamicType, &BaseAspect::changed, this, &GdbEngine::reloadLocals); @@ -2638,6 +2640,7 @@ void GdbEngine::insertBreakpoint(const Breakpoint &bp) const DebuggerSettings &s = settings(); cmd.arg("passexceptions", alwaysVerbose); cmd.arg("fancy", s.useDebuggingHelpers()); + cmd.arg("allowinferiorcalls", s.allowInferiorCalls()); cmd.arg("autoderef", s.autoDerefPointers()); cmd.arg("dyntype", s.useDynamicType()); cmd.arg("qobjectnames", s.showQObjectNames()); @@ -5164,6 +5167,7 @@ void GdbEngine::doUpdateLocals(const UpdateParameters ¶ms) const DebuggerSettings &s = settings(); cmd.arg("passexceptions", alwaysVerbose); cmd.arg("fancy", s.useDebuggingHelpers()); + cmd.arg("allowinferiorcalls", s.allowInferiorCalls()); cmd.arg("autoderef", s.autoDerefPointers()); cmd.arg("dyntype", s.useDynamicType()); cmd.arg("qobjectnames", s.showQObjectNames());