[Lldb-commits] [lldb] bbe3c47 - [lldb] Fix a crash when tab-completion an empty line in a function with only one local variable

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Fri Aug 14 00:07:17 PDT 2020


Author: Raphael Isemann
Date: 2020-08-14T09:06:52+02:00
New Revision: bbe3c479a6adf0abfe5d111e9ba206daa5a1eb2b

URL: https://github.com/llvm/llvm-project/commit/bbe3c479a6adf0abfe5d111e9ba206daa5a1eb2b
DIFF: https://github.com/llvm/llvm-project/commit/bbe3c479a6adf0abfe5d111e9ba206daa5a1eb2b.diff

LOG: [lldb] Fix a crash when tab-completion an empty line in a function with only one local variable

When LLDB sees only one possible completion for an input, it will add a trailing
space to the completion to signal that to the user. If the current argument is
quoted, that also means LLDB needs to add the trailing quote to finish the
current argument first.

In case the user is in a function with only one local variable and is currently
editing an empty line in the multiline expression editor, then we are in the
unique situation where we can have a unique completion for an empty input line.
(In a normal LLDB session this would never occur as empty input would just list
all the possible commands).

In this special situation our check if the current argument needs to receive a
trailing quote will crash LLDB as there is no current argument and the
completion code just unconditionally tries to access the current argument. This
just adds the missing check if we even have a current argument before we check
if we need to add a terminating quote character.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D85903

Added: 
    

Modified: 
    lldb/source/Host/common/Editline.cpp
    lldb/test/API/commands/expression/multiline-completion/TestMultilineCompletion.py
    lldb/test/API/commands/expression/multiline-completion/main.c

Removed: 
    


################################################################################
diff  --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp
index 49b7a38d8dae..1e1bcb0ac7c6 100644
--- a/lldb/source/Host/common/Editline.cpp
+++ b/lldb/source/Host/common/Editline.cpp
@@ -1004,7 +1004,8 @@ unsigned char Editline::TabCommand(int ch) {
     case CompletionMode::Normal: {
       std::string to_add = completion.GetCompletion();
       to_add = to_add.substr(request.GetCursorArgumentPrefix().size());
-      if (request.GetParsedArg().IsQuoted())
+      // Terminate the current argument with a quote if it started with a quote.
+      if (!request.GetParsedLine().empty() && request.GetParsedArg().IsQuoted())
         to_add.push_back(request.GetParsedArg().GetQuoteChar());
       to_add.push_back(' ');
       el_insertstr(m_editline, to_add.c_str());

diff  --git a/lldb/test/API/commands/expression/multiline-completion/TestMultilineCompletion.py b/lldb/test/API/commands/expression/multiline-completion/TestMultilineCompletion.py
index e4935d0e2b84..3e2663d9bdfe 100644
--- a/lldb/test/API/commands/expression/multiline-completion/TestMultilineCompletion.py
+++ b/lldb/test/API/commands/expression/multiline-completion/TestMultilineCompletion.py
@@ -11,6 +11,21 @@ class MultilineCompletionTest(PExpectTest):
 
     mydir = TestBase.compute_mydir(__file__)
 
+    def start_expression_editor(self):
+        """ Starts the multiline expression editor. """
+        self.child.send("expression\n")
+        self.child.expect_exact("terminate with an empty line to evaluate")
+
+    def exit_expression_editor(self):
+        """ Exits the multiline expression editor. """
+        # Send a newline to finish the current line. The second newline will
+        # finish the new empty line which will exit the editor. The space at the
+        # start prevents that the first newline already exits the editor (in
+        # case the current line of the editor is already empty when this
+        # function is called).
+        self.child.send(" \n\n")
+        self.expect_prompt()
+
     # PExpect uses many timeouts internally and doesn't play well
     # under ASAN on a loaded machine..
     @skipIfAsan
@@ -21,14 +36,23 @@ def test_basic_completion(self):
 
         self.launch(executable=self.getBuildArtifact("a.out"), dimensions=(100,500))
         self.expect("b main", substrs=["Breakpoint 1", "address ="])
-        self.expect("run", substrs=["stop reason ="])
+        self.expect("run", substrs=["stop reason = breakpoint 1"])
 
-        self.child.sendline("expr")
-        self.child.expect_exact("terminate with an empty line to evaluate")
+        self.start_expression_editor()
         self.child.send("to_\t")
         self.child.expect_exact("to_complete")
-
-        self.child.send("\n\n")
-        self.expect_prompt()
+        self.exit_expression_editor()
+
+        # Check that completion empty input in a function with only one
+        # local variable works.
+        self.expect("breakpoint set -p 'break in single_local_func'",
+                    substrs=["Breakpoint 2"])
+        self.expect("continue", substrs=["stop reason = breakpoint 2"])
+        self.start_expression_editor()
+        self.child.send("\t")
+        # Only one local, so this will directly insert 'only_local' with a
+        # trailing space to signal a final completion.
+        self.child.expect_exact("only_local ")
+        self.exit_expression_editor()
 
         self.quit()

diff  --git a/lldb/test/API/commands/expression/multiline-completion/main.c b/lldb/test/API/commands/expression/multiline-completion/main.c
index 6dd3616c1ae4..071c02dfe739 100644
--- a/lldb/test/API/commands/expression/multiline-completion/main.c
+++ b/lldb/test/API/commands/expression/multiline-completion/main.c
@@ -1,4 +1,11 @@
+int single_local_func() {
+  // This function should always only have a single local variable and no
+  // parameters.
+  int only_local = 3;
+  return only_local; // break in single_local_func
+}
+
 int main(int argc, char **argv) {
   int to_complete = 0;
-  return to_complete;
+  return to_complete + single_local_func();
 }


        


More information about the lldb-commits mailing list