Debugger: Fix hitting breakpoints repeatedly in multithreading

This change resolves an issue where gdb.parse_and_eval could
rerun the  multithreading application, causing breakpoints to be hit
repeatedly in different threads, leading to an infinite loop.

Added checkbox which enables skipping the execution of
gdb.parse_and_eval in few places that mitigate the issue.

Fixes: QTCREATORBUG-23219
Change-Id: I856d382d033f8a4da394d7422ebb3e131de28e09
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Artem Sokolovskii
2024-10-10 17:02:12 +02:00
parent 5d1d4d9f54
commit a9e8b106a4
7 changed files with 25 additions and 0 deletions

View File

@@ -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'))

View File

@@ -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

View File

@@ -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,

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 &params)
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());