Genex: Fix stack overflow in transitive property evaluation.

Commit v2.8.11~156^2~2 (Expand includes and defines transitively
in 'external' genexes., 2013-02-13) introduced a recursive loop
and a stack overflow during evaluation of a link implementation
which depends on a transitive property, such as

 add_library(empty1 ...)
 add_library(empty2 ...)
 target_link_libraries(empty1
   PRIVATE
     $<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
 )

There is no use-case for code like that currently, but it should not
cause a stack overflow.

Avoid the recursion by reporting an error early if a case like this
is found.
This commit is contained in:
Stephen Kelly 2014-05-11 16:04:53 +02:00
parent bf5fc1d582
commit 61ce654742
21 changed files with 141 additions and 0 deletions

View File

@ -1028,6 +1028,19 @@ static const struct TargetPropertyNode : public cmGeneratorExpressionNode
{
if (dagCheckerParent->EvaluatingLinkLibraries())
{
#define TRANSITIVE_PROPERTY_COMPARE(PROPERTY) \
(#PROPERTY == propertyName || "INTERFACE_" #PROPERTY == propertyName) ||
if (CM_FOR_EACH_TRANSITIVE_PROPERTY_NAME(TRANSITIVE_PROPERTY_COMPARE)
false)
{
reportError(context, content->GetOriginalExpression(),
"$<TARGET_PROPERTY:...> expression in link libraries "
"evaluation depends on target property which is transitive "
"over the link libraries, creating a recursion.");
return std::string();
}
#undef TRANSITIVE_PROPERTY_COMPARE
if(!prop)
{
return std::string();

View File

@ -0,0 +1,10 @@
CMake Error at LinkImplementationCycle1.cmake:5 \(target_link_libraries\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>
\$<TARGET_PROPERTY:...> expression in link libraries evaluation depends on
target property which is transitive over the link libraries, creating a
recursion.
Call Stack \(most recent call first\):
CMakeLists.txt:8 \(include\)

View File

@ -0,0 +1,8 @@
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
target_link_libraries(empty1
LINK_PUBLIC
$<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)

View File

@ -0,0 +1,10 @@
CMake Error at LinkImplementationCycle2.cmake:5 \(target_link_libraries\):
Error evaluating generator expression:
\$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>
\$<TARGET_PROPERTY:...> expression in link libraries evaluation depends on
target property which is transitive over the link libraries, creating a
recursion.
Call Stack \(most recent call first\):
CMakeLists.txt:8 \(include\)

View File

@ -0,0 +1,8 @@
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
target_link_libraries(empty1
LINK_PUBLIC
$<$<STREQUAL:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)

View File

@ -0,0 +1,10 @@
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
# This is OK, because evaluating the INCLUDE_DIRECTORIES is not affected by
# the content of the INTERFACE_LINK_LIBRARIES.
target_link_libraries(empty1
INTERFACE
$<$<STREQUAL:$<TARGET_PROPERTY:INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)

View File

@ -0,0 +1,8 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>
\$<TARGET_PROPERTY:...> expression in link libraries evaluation depends on
target property which is transitive over the link libraries, creating a
recursion.

View File

@ -0,0 +1,14 @@
add_library(empty1 empty.cpp)
add_library(empty2 empty.cpp)
# The INTERFACE_INCLUDE_DIRECTORIES do not depend on the link interface.
# On its own, this is fine. It is only when used by empty3 that an error
# is appropriately issued.
target_link_libraries(empty1
INTERFACE
$<$<STREQUAL:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
add_library(empty3 empty.cpp)
target_link_libraries(empty3 empty1)

View File

@ -0,0 +1,8 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>
\$<TARGET_PROPERTY:...> expression in link libraries evaluation depends on
target property which is transitive over the link libraries, creating a
recursion.

View File

@ -0,0 +1,10 @@
add_library(empty1 INTERFACE IMPORTED)
add_library(empty2 INTERFACE IMPORTED)
set_property(TARGET empty1 PROPERTY INTERFACE_LINK_LIBRARIES
$<$<STREQUAL:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
add_library(empty3 empty.cpp)
target_link_libraries(empty3 empty1)

View File

@ -0,0 +1,8 @@
CMake Error:
Error evaluating generator expression:
\$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>
\$<TARGET_PROPERTY:...> expression in link libraries evaluation depends on
target property which is transitive over the link libraries, creating a
recursion.

View File

@ -0,0 +1,14 @@
add_library(empty1 SHARED empty.cpp)
add_library(empty2 SHARED empty.cpp)
# The INTERFACE_INCLUDE_DIRECTORIES do not depend on the link interface.
# On its own, this is fine. It is only when used by empty3 that an error
# is appropriately issued.
target_link_libraries(empty1
INTERFACE
$<$<STREQUAL:$<TARGET_PROPERTY:INTERFACE_INCLUDE_DIRECTORIES>,/foo/bar>:empty2>
)
add_library(empty3 SHARED empty.cpp)
target_link_libraries(empty3 empty1)

View File

@ -15,3 +15,9 @@ run_cmake(BadInvalidName5)
run_cmake(BadInvalidName6)
run_cmake(BadInvalidName7)
run_cmake(BadInvalidName8)
run_cmake(LinkImplementationCycle1)
run_cmake(LinkImplementationCycle2)
run_cmake(LinkImplementationCycle3)
run_cmake(LinkImplementationCycle4)
run_cmake(LinkImplementationCycle5)
run_cmake(LinkImplementationCycle6)

View File

@ -0,0 +1,7 @@
#ifdef _WIN32
__declspec(dllexport)
#endif
int empty()
{
return 0;
}