Просмотр исходного кода

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 лет назад
Родитель
Сommit
e7230c71fd

+ 24 - 13
Source/cmGeneratorExpressionParser.cxx

@@ -77,6 +77,7 @@ static void extendResult(std::vector<cmGeneratorExpressionEvaluator*> &result,
 void cmGeneratorExpressionParser::ParseGeneratorExpression(
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
 {
+  assert(this->it != this->Tokens.end());
   unsigned int nestedLevel = this->NestingLevel;
   ++this->NestingLevel;
 
@@ -98,7 +99,8 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
     // ERROR
     }
 
-  if (this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
+  if (this->it != this->Tokens.end() &&
+      this->it->TokenType == cmGeneratorExpressionToken::EndExpression)
     {
     GeneratorExpressionContent *content = new GeneratorExpressionContent(
                 startToken->Content, this->it->Content
@@ -115,42 +117,50 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
   std::vector<std::vector<cmGeneratorExpressionToken>::const_iterator>
                                                             commaTokens;
   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;
     parameters.resize(parameters.size() + 1);
     ++this->it;
-    while (this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
+
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType == cmGeneratorExpressionToken::CommaSeparator)
       {
       commaTokens.push_back(this->it);
       parameters.resize(parameters.size() + 1);
       ++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);
       ++this->it;
       }
-    while(this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
+    while (this->it != this->Tokens.end() &&
+           this->it->TokenType != cmGeneratorExpressionToken::EndExpression)
       {
       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);
         parameters.resize(parameters.size() + 1);
         ++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);
         ++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->it;
@@ -201,6 +211,7 @@ void cmGeneratorExpressionParser::ParseGeneratorExpression(
 void cmGeneratorExpressionParser::ParseContent(
                         std::vector<cmGeneratorExpressionEvaluator*> &result)
 {
+  assert(this->it != this->Tokens.end());
   switch(this->it->TokenType)
     {
     case cmGeneratorExpressionToken::Text:
@@ -245,5 +256,5 @@ void cmGeneratorExpressionParser::ParseContent(
       ++this->it;
       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_4=$<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
   COMMAND ${CMAKE_COMMAND} -E echo "check done"
   VERBATIM

+ 22 - 0
Tests/GeneratorExpression/check.cmake

@@ -50,3 +50,25 @@ check(test_colons_2 "::")
 check(test_colons_3 "Qt5::Core")
 check(test_colons_4 "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")