فهرست منبع

GenEx: Fix termination bugs in generator expression parser.

Content which is incomplete as a generator expression could cause
segfaults by advancing an iterator beyond end() and dereferencing
it. Such incomplete generator expressions  should be treated as
plain text instead.
Stephen Kelly 13 سال پیش
والد
کامیت
e7230c71fd
3فایلهای تغییر یافته به همراه68 افزوده شده و 13 حذف شده
  1. 24 13
      Source/cmGeneratorExpressionParser.cxx
  2. 22 0
      Tests/GeneratorExpression/CMakeLists.txt
  3. 22 0
      Tests/GeneratorExpression/check.cmake

+ 24 - 13
Source/cmGeneratorExpressionParser.cxx

@@ -77,6 +77,7 @@ static void extendResult(std::vector<cmGeneratorExpressionEvaluator*> &result,
 void cmGeneratorExpressionParser::ParseGeneratorExpression(
 void cmGeneratorExpressionParser::ParseGeneratorExpression(
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
 {
 {
+  assert(this->it != this->Tokens.end());
   unsigned int nestedLevel = this->NestingLevel;
   unsigned int nestedLevel = this->NestingLevel;
   ++this->NestingLevel;
   ++this->NestingLevel;
 
 
@@ -98,7 +99,8 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
     // ERROR
     // ERROR
     }
     }
 
 
-  if (this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
+  if (this->it != this->Tokens.end() &&
+      this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
     {
     {
     GeneratorExpressionContent *content = new GeneratorExpressionContent(
     GeneratorExpressionContent *content = new GeneratorExpressionContent(
                 startToken->Content, this->it->Content
                 startToken->Content, this->it->Content
@@ -115,42 +117,50 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
                                                             commaTokens;
                                                             commaTokens;
   std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
   std::vector<cmGeneratorExpressionToken>::const_iterator colonToken;
-  if (this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
+  if (this->it != this->Tokens.end() &&
+      this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
     {
     {
     colonToken = this->it;
     colonToken = this->it;
     parameters.resize(parameters.size() + 1);
     parameters.resize(parameters.size() + 1);
     ++this->it;
     ++this->it;
-    while (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
+
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
       {
       {
       commaTokens.push_back(this->it);
       commaTokens.push_back(this->it);
       parameters.resize(parameters.size() + 1);
       parameters.resize(parameters.size() + 1);
       ++this->it;
       ++this->it;
       }
       }
-    while (this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
       {
       {
       extendText(*(parameters.end() - 1), this->it);
       extendText(*(parameters.end() - 1), this->it);
       ++this->it;
       ++this->it;
       }
       }
-    while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
       {
       {
       this->ParseContent(*(parameters.end() - 1));
       this->ParseContent(*(parameters.end() - 1));
-      while (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
+      if (this->it == this->Tokens.end())
+        {
+        break;
+        }
+      while (this->it != this->Tokens.end() &&
+             this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
         {
         {
         commaTokens.push_back(this->it);
         commaTokens.push_back(this->it);
         parameters.resize(parameters.size() + 1);
         parameters.resize(parameters.size() + 1);
         ++this->it;
         ++this->it;
         }
         }
-      while (this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
+      while (this->it != this->Tokens.end() &&
+             this->it->TokenType == cmGeneratorExpressionToken::ColonSeparator)
         {
         {
         extendText(*(parameters.end() - 1), this->it);
         extendText(*(parameters.end() - 1), this->it);
         ++this->it;
         ++this->it;
         }
         }
-      if (this->it == this->Tokens.end())
-        {
-        break;
-        }
       }
       }
-      if(this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
+      if(this->it != this->Tokens.end()
+          && this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
         {
         {
         --this->NestingLevel;
         --this->NestingLevel;
         ++this->it;
         ++this->it;
@@ -201,6 +211,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
 void cmGeneratorExpressionParser::ParseContent(
 void cmGeneratorExpressionParser::ParseContent(
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
 {
 {
+  assert(this->it != this->Tokens.end());
   switch(this->it->TokenType)
   switch(this->it->TokenType)
     {
     {
     case cmGeneratorExpressionToken::Text:
     case cmGeneratorExpressionToken::Text:
@@ -245,5 +256,5 @@ void cmGeneratorExpressionParser::ParseContent(
       ++this->it;
       ++this->it;
       return;
       return;
     }
     }
-  // Unreachable. Assert?
+    assert(!"Unhandled token in generator expression.");
 }
 }

+ 22 - 0
Tests/GeneratorExpression/CMakeLists.txt

@@ -49,6 +49,28 @@ add_custom_target(check ALL
     -Dtest_colons_3=$<1:Qt5::Core>
     -Dtest_colons_3=$<1:Qt5::Core>
     -Dtest_colons_4=$<1:C:\\CMake>
     -Dtest_colons_4=$<1:C:\\CMake>
     -Dtest_colons_5=$<1:C:/CMake>
     -Dtest_colons_5=$<1:C:/CMake>
+    -Dtest_incomplete_1=$<
+    -Dtest_incomplete_2=$<something
+    -Dtest_incomplete_3=$<something:
+    -Dtest_incomplete_4=$<something:,
+    -Dtest_incomplete_5=$something:,>
+    -Dtest_incomplete_6=<something:,>
+    -Dtest_incomplete_7=$<something::
+    -Dtest_incomplete_8=$<something:,
+    -Dtest_incomplete_9=$<something:,,
+    -Dtest_incomplete_10=$<something:,:
+    -Dtest_incomplete_11=$<something,,
+    -Dtest_incomplete_12=$<,,
+    -Dtest_incomplete_13=$<some$<1:special>thing
+    -Dtest_incomplete_14=$<<something
+    -Dtest_incomplete_15=$<some$<thing
+    -Dtest_incomplete_16=$<<some$<thing
+    -Dtest_incomplete_17=$<1:some$thing>
+    -Dtest_incomplete_18=$<1:some,thing
+    -Dtest_incomplete_19=$<1:some,thing$<ANGLE-R>
+    -Dtest_incomplete_20=$<CONFIGURATION$<ANGLE-R>
+    -Dtest_incomplete_21=$<BOOL:something$<ANGLE-R>
+    -Dtest_incomplete_22=$<BOOL:something
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
     -P ${CMAKE_CURRENT_SOURCE_DIR}/check.cmake
   COMMAND ${CMAKE_COMMAND} -E echo "check done"
   COMMAND ${CMAKE_COMMAND} -E echo "check done"
   VERBATIM
   VERBATIM

+ 22 - 0
Tests/GeneratorExpression/check.cmake

@@ -50,3 +50,25 @@ check(test_colons_2 "::")
 check(test_colons_3 "Qt5::Core")
 check(test_colons_3 "Qt5::Core")
 check(test_colons_4 "C:\\\\CMake")
 check(test_colons_4 "C:\\\\CMake")
 check(test_colons_5 "C:/CMake")
 check(test_colons_5 "C:/CMake")
+check(test_incomplete_1 "$<")
+check(test_incomplete_2 "$<something")
+check(test_incomplete_3 "$<something:")
+check(test_incomplete_4 "$<something:,")
+check(test_incomplete_5 "$something:,>")
+check(test_incomplete_6 "<something:,>")
+check(test_incomplete_7 "$<something::")
+check(test_incomplete_8 "$<something:,")
+check(test_incomplete_9 "$<something:,,")
+check(test_incomplete_10 "$<something:,:")
+check(test_incomplete_11 "$<something,,")
+check(test_incomplete_12 "$<,,")
+check(test_incomplete_13 "$<somespecialthing")
+check(test_incomplete_14 "$<<something")
+check(test_incomplete_15 "$<some$<thing")
+check(test_incomplete_16 "$<<some$<thing")
+check(test_incomplete_17 "some$thing")
+check(test_incomplete_18 "$<1:some,thing")
+check(test_incomplete_19 "$<1:some,thing>")
+check(test_incomplete_20 "$<CONFIGURATION>")
+check(test_incomplete_21 "$<BOOL:something>")
+check(test_incomplete_22 "$<BOOL:something")