Reapply "Fix a crash in option parsing."
authorAdrian Prantl <aprantl@apple.com>
Tue, 25 Jun 2019 00:55:27 +0000 (00:55 +0000)
committerAdrian Prantl <aprantl@apple.com>
Tue, 25 Jun 2019 00:55:27 +0000 (00:55 +0000)
with an additional read-out-of-bounds bugfix applied.

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

llvm-svn: 364260

lldb/lit/Driver/Inputs/process_attach_pid.in [new file with mode: 0644]
lldb/lit/Driver/TestProcessAttach.test [new file with mode: 0644]
lldb/source/Interpreter/Options.cpp

diff --git a/lldb/lit/Driver/Inputs/process_attach_pid.in b/lldb/lit/Driver/Inputs/process_attach_pid.in
new file mode 100644 (file)
index 0000000..3d17cee
--- /dev/null
@@ -0,0 +1,2 @@
+process attach --pid
+
diff --git a/lldb/lit/Driver/TestProcessAttach.test b/lldb/lit/Driver/TestProcessAttach.test
new file mode 100644 (file)
index 0000000..4e24ebb
--- /dev/null
@@ -0,0 +1,2 @@
+# RUN: %lldb -x -b -S %S/Inputs/process_attach_pid.in 2>&1 | FileCheck %s
+# CHECK: last option requires an argument
index 814998ec68fc3aac584ceb5bb7feafcb9dd583d7..bd9b47fadd4f48f3162851bd3c93d91b58e6a643 100644 (file)
@@ -1355,13 +1355,23 @@ llvm::Expected<Args> Options::Parse(const Args &args,
     }
   }
   std::vector<char *> argv = GetArgvForParsing(args);
+  // If the last option requires an argument but doesn't have one,
+  // some implementations of getopt_long will still try to read it.
+  char overflow = 0;
+  argv.push_back(&overflow);
   std::unique_lock<std::mutex> lock;
   OptionParser::Prepare(lock);
   int val;
   while (true) {
     int long_options_index = -1;
-    val = OptionParser::Parse(argv.size(), &*argv.begin(), sstr.GetString(),
+    val = OptionParser::Parse(argv.size() - 1, &*argv.begin(), sstr.GetString(),
                               long_options, &long_options_index);
+
+    if ((size_t)OptionParser::GetOptionIndex() > argv.size() - 1) {
+      error.SetErrorStringWithFormat("last option requires an argument");
+      break;
+    }
+
     if (val == -1)
       break;
 
@@ -1439,6 +1449,7 @@ llvm::Expected<Args> Options::Parse(const Args &args,
   if (error.Fail())
     return error.ToError();
 
+  argv.pop_back();
   argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex());
   return ReconstituteArgsAfterParsing(argv, args);
 }