From 6ffc4323670f3671f262b3e9f035f1ea3f714986 Mon Sep 17 00:00:00 2001 From: Brad King Date: Mon, 1 Feb 2016 09:49:08 -0500 Subject: [PATCH] cmConditionEvaluator: Fix matching of `CMAKE_MATCH_*` values (#15944) While evaluating `if(MATCHES)` we get a `const char*` pointer to the string to be matched. On code like if(CMAKE_MATCH_COUNT MATCHES "Y") the string to be matched may be owned by our own result variables. We must move the value to our own buffer before clearing them. Otherwise we risk reading freed storage. --- Source/cmConditionEvaluator.cxx | 10 ++++++++++ Tests/RunCMake/if/MatchesSelf.cmake | 4 ++++ Tests/RunCMake/if/RunCMakeTest.cmake | 2 ++ 3 files changed, 16 insertions(+) create mode 100644 Tests/RunCMake/if/MatchesSelf.cmake diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 5330acdaf..6a0ebec2d 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -12,6 +12,7 @@ #include "cmConditionEvaluator.h" #include "cmOutputConverter.h" +#include "cmAlgorithms.h" cmConditionEvaluator::cmConditionEvaluator(cmMakefile& makefile, const cmListFileContext &context, @@ -578,6 +579,7 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, cmake::MessageType &status) { int reducible; + std::string def_buf; const char *def; const char *def2; do @@ -594,6 +596,14 @@ bool cmConditionEvaluator::HandleLevel2(cmArgumentList &newArgs, IsKeyword("MATCHES", *argP1)) { def = this->GetVariableOrString(*arg); + if (def != arg->c_str() // yes, we compare the pointer value + && cmHasLiteralPrefix(arg->GetValue(), "CMAKE_MATCH_")) + { + // The string to match is owned by our match result variables. + // Move it to our own buffer before clearing them. + def_buf = def; + def = def_buf.c_str(); + } const char* rex = argP2->c_str(); this->Makefile.ClearMatches(); cmsys::RegularExpression regEntry; diff --git a/Tests/RunCMake/if/MatchesSelf.cmake b/Tests/RunCMake/if/MatchesSelf.cmake new file mode 100644 index 000000000..3131ac4f4 --- /dev/null +++ b/Tests/RunCMake/if/MatchesSelf.cmake @@ -0,0 +1,4 @@ +foreach(n 0 1 2 3 4 5 6 7 8 9 COUNT) + if(CMAKE_MATCH_${n} MATCHES "x") + endif() +endforeach() diff --git a/Tests/RunCMake/if/RunCMakeTest.cmake b/Tests/RunCMake/if/RunCMakeTest.cmake index 3f4d2a24d..077d00a05 100644 --- a/Tests/RunCMake/if/RunCMakeTest.cmake +++ b/Tests/RunCMake/if/RunCMakeTest.cmake @@ -5,5 +5,7 @@ run_cmake(IsDirectory) run_cmake(IsDirectoryLong) run_cmake(elseif-message) +run_cmake(MatchesSelf) + run_cmake(TestNameThatExists) run_cmake(TestNameThatDoesNotExist)