-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[lldb][Expression] Reject languages not supported by TypeSystems for expression evaluation #156648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…expression evaluation There are some languages for which the `ClangExpressionParser` currently switches the language type behind a user's back. Specifically, `C` gets turned into `C++` and `ObjC` into `ObjC++`. That's because the Clang expression evaluator depends on C++ features. These languages have different semantics, so if, e.g., a user forcefully wants to evaluate an expression in `C`, but we switch it to `C++`, we get reports from users confused why the expression failed. This patch rejects languages specified with `expression --language` that we won't be able to explicitly evaluate. rdar://159669244
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was initially hesitant to make this a hard error, but the fact that we already have a list of supported languages and that C is not in there makes me more confident in erroring here. Would be curious to hear other's thoughts.
StreamString sstr; | ||
sstr.Printf("unknown language type: '%s' for expression. " | ||
sstr.Printf("invalid language '%s' for expression. " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way to clarify what invalid
means in this context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in latest commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes sense. Does this also mean we can delete some language auto-upgrading code somewhere?
For C in particular we have a "half-way between" mode where we allowed some keywords (like
That seems useful, does this patch break that feature? |
BTW, if this patch breaks that feature w/o some test catching it, we should add a test for these allowed keywords. |
Not yet, that code still is in place so that we can evaluate expressions in C frames. But it gets us a tiny step closer i guess |
This patch doesn't break said feature. It only breaks if you explicitly pass This is what your example now would look like:
|
@llvm/pr-subscribers-lldb Author: Michael Buch (Michael137) ChangesThere are some languages for which the This patch rejects languages specified with rdar://159669244 Full diff: https://github.com/llvm/llvm-project/pull/156648.diff 3 Files Affected:
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 197bffe9c982f..1b951603563ac 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -44,18 +44,26 @@ Status CommandObjectExpression::CommandOptions::SetOptionValue(
const int short_option = GetDefinitions()[option_idx].short_option;
switch (short_option) {
- case 'l':
+ case 'l': {
language = Language::GetLanguageTypeFromString(option_arg);
- if (language == eLanguageTypeUnknown) {
- StreamString sstr;
- sstr.Printf("unknown language type: '%s' for expression. "
- "List of supported languages:\n",
+ if (const LanguageSet supported_languages =
+ Language::GetLanguagesSupportingTypeSystemsForExpressions();
+ supported_languages[language])
+ break;
+
+ StreamString sstr;
+ if (language == eLanguageTypeUnknown)
+ sstr.Printf("unknown language '%s' for expression. ",
+ option_arg.str().c_str());
+ else
+ sstr.Printf("language '%s' is currently not supported for expression "
+ "evaluation. ",
option_arg.str().c_str());
- Language::PrintSupportedLanguagesForExpressions(sstr, " ", "\n");
- error = Status(sstr.GetString().str());
- }
- break;
+ sstr.PutCString("List of supported languages for expressions:\n");
+ Language::PrintSupportedLanguagesForExpressions(sstr, " ", "\n");
+ error = Status(sstr.GetString().str());
+ } break;
case 'a': {
bool success;
diff --git a/lldb/test/API/commands/expression/calculator_mode/TestCalculatorMode.py b/lldb/test/API/commands/expression/calculator_mode/TestCalculatorMode.py
index 138027507c7a7..f12b5b0a12814 100644
--- a/lldb/test/API/commands/expression/calculator_mode/TestCalculatorMode.py
+++ b/lldb/test/API/commands/expression/calculator_mode/TestCalculatorMode.py
@@ -21,7 +21,7 @@ def test__calculator_mode(self):
)
# Now try it with a specific language:
self.expect(
- "expression -l c -- 11 + 22",
+ "expression -l c++ -- 11 + 22",
"11 + 22 didn't get the expected result",
substrs=["33"],
)
diff --git a/lldb/test/API/commands/expression/invalid-args/TestInvalidArgsExpression.py b/lldb/test/API/commands/expression/invalid-args/TestInvalidArgsExpression.py
index 344aef318d783..f0d1542d783b1 100644
--- a/lldb/test/API/commands/expression/invalid-args/TestInvalidArgsExpression.py
+++ b/lldb/test/API/commands/expression/invalid-args/TestInvalidArgsExpression.py
@@ -10,8 +10,20 @@ def test_invalid_lang(self):
"expression -l foo --",
error=True,
substrs=[
- "error: unknown language type: 'foo' for expression",
- "List of supported languages:",
+ "error: unknown language 'foo' for expression.",
+ "List of supported languages for expressions:",
+ "c++",
+ "c++11",
+ "c++14",
+ ],
+ )
+
+ self.expect(
+ "expression -l c --",
+ error=True,
+ substrs=[
+ "error: language 'c' is currently not supported for expression evaluation.",
+ "List of supported languages for expressions:",
"c++",
"c++11",
"c++14",
|
That seems weird. I would expect that the frame choosing the language and the user choosing a language would have identical effects. |
How do we explain that for my global variable (lldb) expr class = 110 works when I happen to be stopped in a C frame, but if I can't find a C frame around there's no way I can replicate that behavior? |
Good question. The reason it works for your example when stopped in a C frame is that the Clang expression evaluator has a workaround in it to allow C++ keywords in pure C/ObjC expressions. If the frame (or before this patch the llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp Lines 848 to 861 in cc36533
But that in itself still has a workaround to make C-expressions work as C++ (because we rely on
But we're still lying to the user about this being pure C expression evaluation. All-in-all, in my opinion, it would be best to keep this workaround contained to just expression evaluation from C/ObjC-frames. If we're stopped in a context where these identifiers were used as variable names, presumably that frame must be a language where this was allowed in. So we would still support the majority of use-cases. The only scenario I can think of that this breaks is that if we're stopped in a C-frame, then declare a top-level variable in the expression context with a reserved identifier in the name, and then switch to a C++ frame and try to use it:
Is that a scenario we want to support? |
The other scenario is accessing an extant C global variable (maybe even one you don't have debug info for) called "class" or "namespace". But more importantly, having this sort of secret out that is applied inconsistently will just make lldb more confusing. It's fine to say "the support for the 'C' language is incomplete" but to treat it inconsistently just makes it harder to understand how lldb is working for you. |
There are some languages for which the
ClangExpressionParser
currently switches the language type behind a user's back. Specifically,C
gets turned intoC++
andObjC
intoObjC++
. That's because the Clang expression evaluator depends on C++ features. These languages have different semantics, so if, e.g., a user forcefully wants to evaluate an expression inC
, but we switch it toC++
, they will most likely wonder why the expression failed (we get reports like this every once in a while...#152113 is a variation of this).This patch rejects languages specified with
expression --language
that we won't be able to explicitly evaluate.rdar://159669244