[Lldb-commits] [lldb] 02114e1 - [lldb] Allow limiting the number of error diagnostics when parsing an expression
Raphael Isemann via lldb-commits
lldb-commits at lists.llvm.org
Tue Oct 13 08:13:03 PDT 2020
Author: Raphael Isemann
Date: 2020-10-13T17:12:43+02:00
New Revision: 02114e15daad7f02e65289412d37334618386ce5
URL: https://github.com/llvm/llvm-project/commit/02114e15daad7f02e65289412d37334618386ce5
DIFF: https://github.com/llvm/llvm-project/commit/02114e15daad7f02e65289412d37334618386ce5.diff
LOG: [lldb] Allow limiting the number of error diagnostics when parsing an expression
While debugging another bug I found out that we currently don't set any limit
for the number of diagnostics Clang emits. If a user does something that
generates a lot of errors (like including some long header file from within the
expression function), then we currently spam the LLDB output with potentially
thousands of Clang error diagnostics.
Clang sets a default limit of 20 errors, but given that LLDB is often used
interactively for small expressions I would say a limit of 5 is enough. The
limit is implemented as a setting, so if a user cares about seeing having a
million errors printed to their terminal then they can just increase the
settings value.
Reviewed By: shafik, mib
Differential Revision: https://reviews.llvm.org/D88889
Added:
lldb/test/API/commands/expression/error-limit/Makefile
lldb/test/API/commands/expression/error-limit/TestExprErrorLimit.py
lldb/test/API/commands/expression/error-limit/main.cpp
Modified:
lldb/include/lldb/Target/Target.h
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
lldb/source/Target/Target.cpp
lldb/source/Target/TargetProperties.td
Removed:
################################################################################
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index f371c4fd6956..0a27147cb61d 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -173,6 +173,8 @@ class TargetProperties : public Properties {
llvm::StringRef GetExpressionPrefixContents();
+ uint64_t GetExprErrorLimit() const;
+
bool GetUseHexImmediates() const;
bool GetUseFastStepping() const;
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 202eb87cca3d..8ad39ecd2707 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -454,6 +454,10 @@ ClangExpressionParser::ClangExpressionParser(
// 4. Create and install the target on the compiler.
m_compiler->createDiagnostics();
+ // Limit the number of error diagnostics we emit.
+ // A value of 0 means no limit for both LLDB and Clang.
+ m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit());
+
auto target_info = TargetInfo::CreateTargetInfo(
m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts);
if (log) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 6ce613697825..5cbdb4995c75 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -4026,6 +4026,12 @@ llvm::StringRef TargetProperties::GetExpressionPrefixContents() {
return "";
}
+uint64_t TargetProperties::GetExprErrorLimit() const {
+ const uint32_t idx = ePropertyExprErrorLimit;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(
+ nullptr, idx, g_target_properties[idx].default_uint_value);
+}
+
bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() {
const uint32_t idx = ePropertyBreakpointUseAvoidList;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td
index 7fb9b105ceef..c624bc35d16e 100644
--- a/lldb/source/Target/TargetProperties.td
+++ b/lldb/source/Target/TargetProperties.td
@@ -20,6 +20,10 @@ let Definition = "target" in {
def ExprPrefix: Property<"expr-prefix", "FileSpec">,
DefaultStringValue<"">,
Desc<"Path to a file containing expressions to be prepended to all expressions.">;
+ def ExprErrorLimit: Property<"expr-error-limit", "UInt64">,
+ DefaultUnsignedValue<5>,
+ Desc<"The maximum amount of errors to emit while parsing an expression. "
+ "A value of 0 means to always continue parsing if possible.">;
def PreferDynamic: Property<"prefer-dynamic-value", "Enum">,
DefaultEnumValue<"eDynamicDontRunTarget">,
EnumValues<"OptionEnumValues(g_dynamic_value_types)">,
diff --git a/lldb/test/API/commands/expression/error-limit/Makefile b/lldb/test/API/commands/expression/error-limit/Makefile
new file mode 100644
index 000000000000..99998b20bcb0
--- /dev/null
+++ b/lldb/test/API/commands/expression/error-limit/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/commands/expression/error-limit/TestExprErrorLimit.py b/lldb/test/API/commands/expression/error-limit/TestExprErrorLimit.py
new file mode 100644
index 000000000000..30e003787ec5
--- /dev/null
+++ b/lldb/test/API/commands/expression/error-limit/TestExprErrorLimit.py
@@ -0,0 +1,60 @@
+"""
+Tests target.expr-error-limit.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @no_debug_info_test
+ def test(self):
+ # FIXME: The only reason this test needs to create a real target is because
+ # the settings of the dummy target can't be changed with `settings set`.
+ self.build()
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+
+ # Our test expression that is just several lines of malformed
+ # integer literals (with a 'yerror' integer suffix). Every error
+ # has its own unique string (1, 2, 3, 4) and is on its own line
+ # that we can later find it when Clang prints the respective source
+ # code for each error to the error output.
+ # For example, in the error output below we would look for the
+ # unique `1yerror` string:
+ # error: <expr>:1:2: invalid suffix 'yerror' on integer constant
+ # 1yerror
+ # ^
+ expr = "1yerror;\n2yerror;\n3yerror;\n4yerror;"
+
+ options = lldb.SBExpressionOptions()
+ options.SetAutoApplyFixIts(False)
+
+ # Evaluate the expression and check that only the first 2 errors are
+ # emitted.
+ self.runCmd("settings set target.expr-error-limit 2")
+ eval_result = target.EvaluateExpression(expr, options)
+ self.assertIn("1yerror", str(eval_result.GetError()))
+ self.assertIn("2yerror", str(eval_result.GetError()))
+ self.assertNotIn("3yerror", str(eval_result.GetError()))
+ self.assertNotIn("4yerror", str(eval_result.GetError()))
+
+ # Change to a 3 errors and check again which errors are emitted.
+ self.runCmd("settings set target.expr-error-limit 3")
+ eval_result = target.EvaluateExpression(expr, options)
+ self.assertIn("1yerror", str(eval_result.GetError()))
+ self.assertIn("2yerror", str(eval_result.GetError()))
+ self.assertIn("3yerror", str(eval_result.GetError()))
+ self.assertNotIn("4yerror", str(eval_result.GetError()))
+
+ # Disable the error limit and make sure all errors are emitted.
+ self.runCmd("settings set target.expr-error-limit 0")
+ eval_result = target.EvaluateExpression(expr, options)
+ self.assertIn("1yerror", str(eval_result.GetError()))
+ self.assertIn("2yerror", str(eval_result.GetError()))
+ self.assertIn("3yerror", str(eval_result.GetError()))
+ self.assertIn("4yerror", str(eval_result.GetError()))
diff --git a/lldb/test/API/commands/expression/error-limit/main.cpp b/lldb/test/API/commands/expression/error-limit/main.cpp
new file mode 100644
index 000000000000..ba45ee316cd4
--- /dev/null
+++ b/lldb/test/API/commands/expression/error-limit/main.cpp
@@ -0,0 +1,3 @@
+int main() {
+ return 0; // break here
+}
More information about the lldb-commits
mailing list