Diagnose recursive project/enable_language without crashing (#15999)

Calling `project()` or `enable_language()` from a toolchain file will
infinitely recurse since those commands load the toolchain file.
Diagnose and reject this case with an error message instead of crashing
when the stack eventually overflows.
This commit is contained in:
Brad King 2016-03-07 13:31:25 -05:00
parent 8256d021c8
commit 72e0dc58d3
13 changed files with 49 additions and 0 deletions

View File

@ -398,6 +398,21 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
return; return;
} }
std::set<std::string> cur_languages(languages.begin(), languages.end());
for (std::set<std::string>::iterator li = cur_languages.begin();
li != cur_languages.end(); ++li)
{
if (!this->LanguagesInProgress.insert(*li).second)
{
std::ostringstream e;
e << "Language '" << *li << "' is currently being enabled. "
"Recursive call not allowed.";
mf->IssueMessage(cmake::FATAL_ERROR, e.str());
cmSystemTools::SetFatalErrorOccured();
return;
}
}
if(this->TryCompileOuterMakefile) if(this->TryCompileOuterMakefile)
{ {
// In a try-compile we can only enable languages provided by caller. // In a try-compile we can only enable languages provided by caller.
@ -823,6 +838,12 @@ cmGlobalGenerator::EnableLanguage(std::vector<std::string>const& languages,
{ {
cmSystemTools::SetFatalErrorOccured(); cmSystemTools::SetFatalErrorOccured();
} }
for (std::set<std::string>::iterator li = cur_languages.begin();
li != cur_languages.end(); ++li)
{
this->LanguagesInProgress.erase(*li);
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -457,6 +457,7 @@ private:
// in EnableLanguagesFromGenerator // in EnableLanguagesFromGenerator
std::map<std::string, bool> IgnoreExtensions; std::map<std::string, bool> IgnoreExtensions;
std::set<std::string> LanguagesReady; // Ready for try_compile std::set<std::string> LanguagesReady; // Ready for try_compile
std::set<std::string> LanguagesInProgress;
std::map<std::string, std::string> OutputExtensions; std::map<std::string, std::string> OutputExtensions;
std::map<std::string, std::string> LanguageToOutputExtension; std::map<std::string, std::string> LanguageToOutputExtension;
std::map<std::string, std::string> ExtensionToLanguage; std::map<std::string, std::string> ExtensionToLanguage;

View File

@ -152,6 +152,7 @@ add_RunCMake_test(ObjectLibrary)
add_RunCMake_test(Swift) add_RunCMake_test(Swift)
add_RunCMake_test(TargetObjects) add_RunCMake_test(TargetObjects)
add_RunCMake_test(TargetSources) add_RunCMake_test(TargetSources)
add_RunCMake_test(ToolchainFile)
add_RunCMake_test(find_dependency) add_RunCMake_test(find_dependency)
add_RunCMake_test(CompileDefinitions) add_RunCMake_test(CompileDefinitions)
add_RunCMake_test(CompileFeatures) add_RunCMake_test(CompileFeatures)

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.5)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
^CMake Error at CallEnableLanguage-toolchain.cmake:[0-9]+ \(enable_language\):
Language 'NONE' is currently being enabled. Recursive call not allowed.
Call Stack \(most recent call first\):
.*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
CMakeLists.txt:[0-9]+ \(project\)$

View File

@ -0,0 +1 @@
enable_language(NONE)

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,5 @@
^CMake Error at CallProject-toolchain.cmake:[0-9]+ \(project\):
Language 'NONE' is currently being enabled. Recursive call not allowed.
Call Stack \(most recent call first\):
.*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(include\)
CMakeLists.txt:[0-9]+ \(project\)$

View File

@ -0,0 +1 @@
project(Bad NONE)

View File

@ -0,0 +1,9 @@
include(RunCMake)
function(run_cmake_toolchain t)
set(RunCMake_TEST_OPTIONS -DCMAKE_TOOLCHAIN_FILE=${RunCMake_SOURCE_DIR}/${t}-toolchain.cmake)
run_cmake(${t})
endfunction()
run_cmake_toolchain(CallEnableLanguage)
run_cmake_toolchain(CallProject)