Skip to content

Commit 6ad660e

Browse files
committed
[lldb] Delay removal of persistent results
Follow up to "Suppress persistent result when running po" (D144044). This change delays removal of the persistent result until after `Dump` has been called. In doing so, the persistent result is available for the purpose of getting its object description. In the original change, the persistent result removal happens indirectly, by setting `EvaluateExpressionOptions::SetSuppressPersistentResult`. In practice this has worked, however this exposed a latent bug in swift-lldb. The subtlety, and the bug, depend on when the persisteted result variable is removed. When the result is removed via `SetSuppressPersistentResult`, it happens within the call to `Target::EvaluateExpression`. That is, by the time the call returns, the persistent result is already removed. The issue occurs shortly thereafter, when `ValueObject::Dump` is called, it cannot make use of the persistent result variable (instead it uses the `ValueObjectConstResult`). In swift-lldb, this causes an additional expression evaluation to happen. It first tries an expression that reference `$R0` etc, but that always fails because `$R0` is removed. The fallback to this failure does work most of the time, but there's at least one bug involving imported Clang types. Differential Revision: https://reviews.llvm.org/D150619 (cherry picked from commit db81455)
1 parent cee7200 commit 6ad660e

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

lldb/source/Commands/CommandObjectDWIMPrint.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "lldb/Core/ValueObject.h"
1212
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
13+
#include "lldb/Expression/ExpressionVariable.h"
1314
#include "lldb/Interpreter/CommandInterpreter.h"
1415
#include "lldb/Interpreter/CommandObject.h"
1516
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -78,28 +79,34 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
7879
// If the user has not specified, default to disabling persistent results.
7980
if (m_expr_options.suppress_persistent_result == eLazyBoolCalculate)
8081
m_expr_options.suppress_persistent_result = eLazyBoolYes;
82+
bool suppress_result = m_expr_options.ShouldSuppressResult(m_varobj_options);
8183

8284
auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
8385

8486
Target *target_ptr = m_exe_ctx.GetTargetPtr();
8587
// Fallback to the dummy target, which can allow for expression evaluation.
8688
Target &target = target_ptr ? *target_ptr : GetDummyTarget();
8789

88-
const EvaluateExpressionOptions eval_options =
90+
EvaluateExpressionOptions eval_options =
8991
m_expr_options.GetEvaluateExpressionOptions(target, m_varobj_options);
92+
// This command manually removes the result variable, make sure expression
93+
// evaluation doesn't do it first.
94+
eval_options.SetSuppressPersistentResult(false);
9095

9196
DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions(
9297
m_expr_options.m_verbosity, m_format_options.GetFormat());
93-
dump_options.SetHideRootName(eval_options.GetSuppressPersistentResult());
98+
dump_options.SetHideRootName(suppress_result);
9499

95100
StackFrame *frame = m_exe_ctx.GetFramePtr();
96101

97102
// First, try `expr` as the name of a frame variable.
98103
if (frame) {
99104
auto valobj_sp = frame->FindVariable(ConstString(expr));
100105
if (valobj_sp && valobj_sp->GetError().Success()) {
101-
if (!eval_options.GetSuppressPersistentResult())
102-
valobj_sp = valobj_sp->Persist();
106+
if (!suppress_result) {
107+
if (auto persisted_valobj = valobj_sp->Persist())
108+
valobj_sp = persisted_valobj;
109+
}
103110

104111
if (verbosity == eDWIMPrintVerbosityFull) {
105112
StringRef flags;
@@ -172,6 +179,16 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef command,
172179
}
173180

174181
valobj_sp->Dump(result.GetOutputStream(), dump_options);
182+
183+
if (suppress_result)
184+
if (auto result_var_sp =
185+
target.GetPersistentVariable(valobj_sp->GetName())) {
186+
auto language = valobj_sp->GetPreferredDisplayLanguage();
187+
if (auto *persistent_state =
188+
target.GetPersistentExpressionStateForLanguage(language))
189+
persistent_state->RemovePersistentVariable(result_var_sp);
190+
}
191+
175192
result.SetStatus(eReturnStatusSuccessFinishResult);
176193
return true;
177194
} else {

lldb/source/Commands/CommandObjectExpression.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "CommandObjectExpression.h"
1212
#include "lldb/Core/Debugger.h"
13+
#include "lldb/Expression/ExpressionVariable.h"
1314
#include "lldb/Expression/REPL.h"
1415
#include "lldb/Expression/UserExpression.h"
1516
#include "lldb/Host/OptionParser.h"
@@ -21,6 +22,7 @@
2122
#include "lldb/Target/Process.h"
2223
#include "lldb/Target/StackFrame.h"
2324
#include "lldb/Target/Target.h"
25+
#include "lldb/lldb-enumerations.h"
2426
#include "lldb/lldb-private-enumerations.h"
2527

2628
// BEGIN SWIFT
@@ -218,13 +220,6 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
218220
const Target &target, const OptionGroupValueObjectDisplay &display_opts) {
219221
EvaluateExpressionOptions options;
220222
options.SetCoerceToId(display_opts.use_objc);
221-
// Explicitly disabling persistent results takes precedence over the
222-
// m_verbosity/use_objc logic.
223-
if (suppress_persistent_result != eLazyBoolCalculate)
224-
options.SetSuppressPersistentResult(suppress_persistent_result ==
225-
eLazyBoolYes);
226-
else if (m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact)
227-
options.SetSuppressPersistentResult(display_opts.use_objc);
228223
options.SetUnwindOnError(unwind_on_error);
229224
options.SetIgnoreBreakpoints(ignore_breakpoints);
230225
options.SetKeepInMemory(true);
@@ -272,6 +267,17 @@ CommandObjectExpression::CommandOptions::GetEvaluateExpressionOptions(
272267
return options;
273268
}
274269

270+
bool CommandObjectExpression::CommandOptions::ShouldSuppressResult(
271+
const OptionGroupValueObjectDisplay &display_opts) const {
272+
// Explicitly disabling persistent results takes precedence over the
273+
// m_verbosity/use_objc logic.
274+
if (suppress_persistent_result != eLazyBoolCalculate)
275+
return suppress_persistent_result == eLazyBoolYes;
276+
277+
return display_opts.use_objc &&
278+
m_verbosity == eLanguageRuntimeDescriptionDisplayVerbosityCompact;
279+
}
280+
275281
CommandObjectExpression::CommandObjectExpression(
276282
CommandInterpreter &interpreter)
277283
: CommandObjectRaw(interpreter, "expression",
@@ -456,8 +462,12 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
456462
return false;
457463
}
458464

459-
const EvaluateExpressionOptions eval_options =
465+
EvaluateExpressionOptions eval_options =
460466
m_command_options.GetEvaluateExpressionOptions(target, m_varobj_options);
467+
// This command manually removes the result variable, make sure expression
468+
// evaluation doesn't do it first.
469+
eval_options.SetSuppressPersistentResult(false);
470+
461471
ExpressionResults success = target.EvaluateExpression(
462472
expr, frame, result_valobj_sp, eval_options, &m_fixed_expression);
463473

@@ -486,14 +496,25 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
486496
}
487497
}
488498

499+
bool suppress_result =
500+
m_command_options.ShouldSuppressResult(m_varobj_options);
501+
489502
DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
490503
m_command_options.m_verbosity, format));
491-
options.SetHideRootName(eval_options.GetSuppressPersistentResult());
504+
options.SetHideRootName(suppress_result);
492505
options.SetVariableFormatDisplayLanguage(
493506
result_valobj_sp->GetPreferredDisplayLanguage());
494507

495508
result_valobj_sp->Dump(output_stream, options);
496509

510+
if (suppress_result)
511+
if (auto result_var_sp =
512+
target.GetPersistentVariable(result_valobj_sp->GetName())) {
513+
auto language = result_valobj_sp->GetPreferredDisplayLanguage();
514+
if (auto *persistent_state =
515+
target.GetPersistentExpressionStateForLanguage(language))
516+
persistent_state->RemovePersistentVariable(result_var_sp);
517+
}
497518
result.SetStatus(eReturnStatusSuccessFinishResult);
498519
}
499520
} else {

lldb/source/Commands/CommandObjectExpression.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class CommandObjectExpression : public CommandObjectRaw,
4141
const Target &target,
4242
const OptionGroupValueObjectDisplay &display_opts);
4343

44+
bool ShouldSuppressResult(
45+
const OptionGroupValueObjectDisplay &display_opts) const;
46+
4447
bool top_level;
4548
bool unwind_on_error;
4649
bool ignore_breakpoints;

0 commit comments

Comments
 (0)