Browse Source

CMakePresets.json: Prohibit empty variable names

Kyle Edwards 5 years ago
parent
commit
a395cb516b

+ 17 - 15
Help/manual/cmake.1.rst

@@ -354,9 +354,10 @@ source and build trees and generate a buildsystem:
 
     ``cacheVariables``
 
-      An optional map of cache variables. The key is the variable name, and the
-      value is either ``null``, a string representing the value of the variable
-      (which supports macro expansion), or an object with the following fields:
+      An optional map of cache variables. The key is the variable name (which
+      may not be an empty string), and the value is either ``null``, a string
+      representing the value of the variable (which supports macro expansion),
+      or an object with the following fields:
 
       ``type``
 
@@ -376,14 +377,14 @@ source and build trees and generate a buildsystem:
 
     ``environment``
 
-      An optional map of environment variables. The key is the variable name,
-      and the value is either ``null`` or a string representing the value of
-      the variable. Each variable is set regardless of whether or not a value
-      was given to it by the process's environment. This field supports macro
-      expansion, and environment variables in this map may reference each
-      other, and may be listed in any order, as long as such references do not
-      cause a cycle (for example, if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2``
-      may not be ``$env{ENV_1}``.)
+      An optional map of environment variables. The key is the variable name
+      (which may not be an empty string), and the value is either ``null`` or
+      a string representing the value of the variable. Each variable is set
+      regardless of whether or not a value was given to it by the process's
+      environment. This field supports macro expansion, and environment
+      variables in this map may reference each other, and may be listed in any
+      order, as long as such references do not cause a cycle (for example,
+      if ``ENV_1`` is ``$env{ENV_2}``, ``ENV_2`` may not be ``$env{ENV_1}``.)
 
       Environment variables are inherited through the ``inherits`` field, and
       the preset's environment will be the union of its own ``environment`` and
@@ -478,10 +479,11 @@ source and build trees and generate a buildsystem:
 
   ``$env{<variable-name>}``
 
-    Environment variable with name ``<variable-name>``. If the variable is
-    defined in the ``environment`` field, that value is used instead of the
-    value from the parent environment. If the environment variable is not
-    defined, this evaluates as an empty string.
+    Environment variable with name ``<variable-name>``. The variable name may
+    not be an empty string. If the variable is defined in the ``environment``
+    field, that value is used instead of the value from the parent environment.
+    If the environment variable is not defined, this evaluates as an empty
+    string.
 
     Note that while Windows environment variable names are case-insensitive,
     variable names within a preset are still case-sensitive. This may lead to

+ 11 - 1
Source/cmCMakePresetsFile.cxx

@@ -305,6 +305,13 @@ ReadFileResult VisitPreset(std::map<std::string, UnexpandedPreset>& presets,
 
   cycleStatus[preset.Name] = CycleStatus::InProgress;
 
+  if (preset.CacheVariables.count("") != 0) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+  if (preset.Environment.count("") != 0) {
+    return ReadFileResult::INVALID_PRESET;
+  }
+
   for (auto const& i : preset.Inherits) {
     auto parent = presets.find(i);
     if (parent == presets.end()) {
@@ -550,7 +557,7 @@ bool ExpandMacro(const cmCMakePresetsFile& file,
     }
   }
 
-  if (macroNamespace == "env") {
+  if (macroNamespace == "env" && !macroName.empty()) {
     auto v = preset.Environment.find(macroName);
     if (v != preset.Environment.end() && v->second) {
       if (!VisitEnv(file, preset, envCycles, *v->second,
@@ -563,6 +570,9 @@ bool ExpandMacro(const cmCMakePresetsFile& file,
   }
 
   if (macroNamespace == "env" || macroNamespace == "penv") {
+    if (macroName.empty()) {
+      return false;
+    }
     const char* value = std::getenv(macroName.c_str());
     if (value) {
       out += value;

+ 16 - 0
Tests/RunCMake/CMakePresets/CMakePresets.json.in

@@ -334,6 +334,22 @@
         "ENV_2": "$env{ENV_1}"
       }
     },
+    {
+      "name": "EmptyEnv",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "MY_VAR": "$env{}"
+      }
+    },
+    {
+      "name": "EmptyPenv",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "MY_VAR": "$penv{}"
+      }
+    },
     {
       "name": "UseHiddenPreset",
       "generator": "@RunCMake_GENERATOR@",

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyCacheKey-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/EmptyCacheKey-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyCacheKey: Invalid preset$

+ 13 - 0
Tests/RunCMake/CMakePresets/EmptyCacheKey.json.in

@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "EmptyCacheKey",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "": "value"
+      }
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyEnv-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyEnv-stderr.txt

@@ -0,0 +1 @@
+^CMake Error: Could not evaluate preset "EmptyEnv": Invalid macro expansion$

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyEnvKey-result.txt

@@ -0,0 +1 @@
+1

+ 2 - 0
Tests/RunCMake/CMakePresets/EmptyEnvKey-stderr.txt

@@ -0,0 +1,2 @@
+^CMake Error: Could not read presets from [^
+]*/Tests/RunCMake/CMakePresets/EmptyEnvKey: Invalid preset$

+ 13 - 0
Tests/RunCMake/CMakePresets/EmptyEnvKey.json.in

@@ -0,0 +1,13 @@
+{
+  "version": 1,
+  "configurePresets": [
+    {
+      "name": "EmptyEnvKey",
+      "generator": "@RunCMake_GENERATOR@",
+      "binaryDir": "${sourceDir}/build",
+      "environment": {
+        "": "value"
+      }
+    }
+  ]
+}

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyPenv-result.txt

@@ -0,0 +1 @@
+1

+ 1 - 0
Tests/RunCMake/CMakePresets/EmptyPenv-stderr.txt

@@ -0,0 +1 @@
+^CMake Error: Could not evaluate preset "EmptyPenv": Invalid macro expansion$

+ 4 - 0
Tests/RunCMake/CMakePresets/RunCMakeTest.cmake

@@ -90,6 +90,8 @@ run_cmake_presets(ErrorNoWarningDev)
 run_cmake_presets(ErrorNoWarningDeprecated)
 run_cmake_presets(InvalidCMakeGeneratorConfig)
 run_cmake_presets(UnknownCMakeGeneratorConfig)
+run_cmake_presets(EmptyCacheKey)
+run_cmake_presets(EmptyEnvKey)
 
 # Test cmakeMinimumRequired field
 run_cmake_presets(MinimumRequiredInvalid)
@@ -143,6 +145,8 @@ run_cmake_presets(NoSuchMacro)
 run_cmake_presets(VendorMacro)
 run_cmake_presets(InvalidGenerator)
 run_cmake_presets(EnvCycle)
+run_cmake_presets(EmptyEnv)
+run_cmake_presets(EmptyPenv)
 
 # Test Visual Studio-specific stuff
 if(RunCMake_GENERATOR MATCHES "^Visual Studio ")