Browse Source

foreach: Fix crash when parsing invalid integer

Fixes: #20393
Kyle Edwards 5 years ago
parent
commit
a33b3949e5

+ 35 - 6
Source/cmForEachCommand.cxx

@@ -12,6 +12,8 @@
 #include <cstdlib>
 #include <cstdlib>
 #include <iterator>
 #include <iterator>
 #include <map>
 #include <map>
+#include <sstream>
+#include <stdexcept>
 #include <utility>
 #include <utility>
 
 
 #include <cm/memory>
 #include <cm/memory>
@@ -354,6 +356,21 @@ bool HandleInMode(std::vector<std::string> const& args,
   return true;
   return true;
 }
 }
 
 
+bool TryParseInteger(cmExecutionStatus& status, const std::string& str, int& i)
+{
+  try {
+    i = std::stoi(str);
+  } catch (std::invalid_argument&) {
+    std::ostringstream e;
+    e << "Invalid integer: '" << str << "'";
+    status.SetError(e.str());
+    cmSystemTools::SetFatalErrorOccured();
+    return false;
+  }
+
+  return true;
+}
+
 } // anonymous namespace
 } // anonymous namespace
 
 
 bool cmForEachCommand(std::vector<std::string> const& args,
 bool cmForEachCommand(std::vector<std::string> const& args,
@@ -376,16 +393,28 @@ bool cmForEachCommand(std::vector<std::string> const& args,
       int stop = 0;
       int stop = 0;
       int step = 0;
       int step = 0;
       if (args.size() == 3) {
       if (args.size() == 3) {
-        stop = std::stoi(args[2]);
+        if (!TryParseInteger(status, args[2], stop)) {
+          return false;
+        }
       }
       }
       if (args.size() == 4) {
       if (args.size() == 4) {
-        start = std::stoi(args[2]);
-        stop = std::stoi(args[3]);
+        if (!TryParseInteger(status, args[2], start)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[3], stop)) {
+          return false;
+        }
       }
       }
       if (args.size() == 5) {
       if (args.size() == 5) {
-        start = std::stoi(args[2]);
-        stop = std::stoi(args[3]);
-        step = std::stoi(args[4]);
+        if (!TryParseInteger(status, args[2], start)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[3], stop)) {
+          return false;
+        }
+        if (!TryParseInteger(status, args[4], step)) {
+          return false;
+        }
       }
       }
       if (step == 0) {
       if (step == 0) {
         if (start > stop) {
         if (start > stop) {

+ 6 - 0
Tests/RunCMake/foreach/RunCMakeTest.cmake

@@ -12,3 +12,9 @@ run_cmake(foreach-ZIP_LISTS-with-LISTS-mix-test)
 run_cmake(foreach-ZIP_LISTS-multiple-iter-vars-test)
 run_cmake(foreach-ZIP_LISTS-multiple-iter-vars-test)
 run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-1)
 run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-1)
 run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-2)
 run_cmake(foreach-ZIP_LISTS-iter-vars-mismatch-test-2)
+run_cmake(foreach-RANGE-non-int-test-1)
+run_cmake(foreach-RANGE-non-int-test-2-1)
+run_cmake(foreach-RANGE-non-int-test-2-2)
+run_cmake(foreach-RANGE-non-int-test-3-1)
+run_cmake(foreach-RANGE-non-int-test-3-2)
+run_cmake(foreach-RANGE-non-int-test-3-3)

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-1.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE b)
+endforeach()

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-2-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-1.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE b 1)
+endforeach()

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-2-2\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-2-2.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE 1 b)
+endforeach()

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-1\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-1.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE b 1 1)
+endforeach()

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-2\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-2.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE 1 b 1)
+endforeach()

+ 1 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-result.txt

@@ -0,0 +1 @@
+1

+ 4 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3-stderr.txt

@@ -0,0 +1,4 @@
+^CMake Error at foreach-RANGE-non-int-test-3-3\.cmake:[0-9]+ \(foreach\):
+  foreach Invalid integer: 'b'
+Call Stack \(most recent call first\):
+  CMakeLists\.txt:3 \(include\)$

+ 2 - 0
Tests/RunCMake/foreach/foreach-RANGE-non-int-test-3-3.cmake

@@ -0,0 +1,2 @@
+foreach(a RANGE 1 1 b)
+endforeach()