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 +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits