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.
This commit is contained in:
parent
145a4af8d3
commit
e7230c71fd
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue