Parcourir la source

Merge topic 'parse-large-int'

8fc822e13a file: Avoid strange istringstream crash in cmake.org binaries on Alpine Linux
31f158e4c8 cmStringAlgorithms: Add functions to parse strings to long long integers

Acked-by: Kitware Robot <[email protected]>
Acked-by: buildbot <[email protected]>
Merge-request: !7698
Brad King il y a 3 ans
Parent
commit
ef1d34b20d

+ 8 - 2
Source/cmFileCommand.cxx

@@ -201,13 +201,19 @@ bool HandleReadCommand(std::vector<std::string> const& args,
   // is there a limit?
   std::string::size_type sizeLimit = std::string::npos;
   if (!arguments.Limit.empty()) {
-    std::istringstream(arguments.Limit) >> sizeLimit;
+    unsigned long long limit;
+    if (cmStrToULongLong(arguments.Limit, &limit)) {
+      sizeLimit = static_cast<std::string::size_type>(limit);
+    }
   }
 
   // is there an offset?
   cmsys::ifstream::off_type offset = 0;
   if (!arguments.Offset.empty()) {
-    std::istringstream(arguments.Offset) >> offset;
+    long long off;
+    if (cmStrToLongLong(arguments.Offset, &off)) {
+      offset = static_cast<cmsys::ifstream::off_type>(off);
+    }
   }
 
   file.seekg(offset, std::ios::beg); // explicit ios::beg for IBM VisualAge 6

+ 32 - 0
Source/cmStringAlgorithms.cxx

@@ -250,6 +250,38 @@ bool cmStrToULong(std::string const& str, unsigned long* value)
   return cmStrToULong(str.c_str(), value);
 }
 
+bool cmStrToLongLong(const char* str, long long* value)
+{
+  errno = 0;
+  char* endp;
+  *value = strtoll(str, &endp, 10);
+  return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToLongLong(std::string const& str, long long* value)
+{
+  return cmStrToLongLong(str.c_str(), value);
+}
+
+bool cmStrToULongLong(const char* str, unsigned long long* value)
+{
+  errno = 0;
+  char* endp;
+  while (cmIsSpace(*str)) {
+    ++str;
+  }
+  if (*str == '-') {
+    return false;
+  }
+  *value = strtoull(str, &endp, 10);
+  return (*endp == '\0') && (endp != str) && (errno == 0);
+}
+
+bool cmStrToULongLong(std::string const& str, unsigned long long* value)
+{
+  return cmStrToULongLong(str.c_str(), value);
+}
+
 template <typename Range>
 std::size_t getJoinedLength(Range const& rng, cm::string_view separator)
 {

+ 10 - 0
Source/cmStringAlgorithms.h

@@ -303,3 +303,13 @@ bool cmStrToLong(std::string const& str, long* value);
  * integer */
 bool cmStrToULong(const char* str, unsigned long* value);
 bool cmStrToULong(std::string const& str, unsigned long* value);
+
+/** Converts a string to long long. Expects that the whole string
+ * is an integer */
+bool cmStrToLongLong(const char* str, long long* value);
+bool cmStrToLongLong(std::string const& str, long long* value);
+
+/** Converts a string to unsigned long long. Expects that the whole string
+ * is an integer */
+bool cmStrToULongLong(const char* str, unsigned long long* value);
+bool cmStrToULongLong(std::string const& str, unsigned long long* value);

+ 35 - 0
Tests/CMakeLib/testStringAlgorithms.cxx

@@ -226,6 +226,41 @@ int testStringAlgorithms(int /*unused*/, char* /*unused*/ [])
               "cmStrToULong rejects trailing content.");
   }
 
+  // ----------------------------------------------------------------------
+  // Test cmStrToLongLong
+  {
+    long long value;
+    assert_ok(cmStrToLongLong("1", &value) && value == 1,
+              "cmStrToLongLong parses a positive decimal integer.");
+    assert_ok(cmStrToLongLong(" 1", &value) && value == 1,
+              "cmStrToLongLong parses a decimal integer after whitespace.");
+
+    assert_ok(cmStrToLongLong("-1", &value) && value == -1,
+              "cmStrToLongLong parses a negative decimal integer.");
+    assert_ok(
+      cmStrToLongLong(" -1", &value) && value == -1,
+      "cmStrToLongLong parses a negative decimal integer after whitespace.");
+
+    assert_ok(!cmStrToLongLong("1x", &value),
+              "cmStrToLongLong rejects trailing content.");
+  }
+
+  // ----------------------------------------------------------------------
+  // Test cmStrToULongLong
+  {
+    unsigned long long value;
+    assert_ok(cmStrToULongLong("1", &value) && value == 1,
+              "cmStrToULongLong parses a decimal integer.");
+    assert_ok(cmStrToULongLong(" 1", &value) && value == 1,
+              "cmStrToULongLong parses a decimal integer after whitespace.");
+    assert_ok(!cmStrToULongLong("-1", &value),
+              "cmStrToULongLong rejects a negative number.");
+    assert_ok(!cmStrToULongLong(" -1", &value),
+              "cmStrToULongLong rejects a negative number after whitespace.");
+    assert_ok(!cmStrToULongLong("1x", &value),
+              "cmStrToULongLong rejects trailing content.");
+  }
+
   // ----------------------------------------------------------------------
   // Test cmStrLen
   {