From ebda994e59e50db377b7532b530e3b7cfb1a2cd4 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Tue, 3 Mar 2020 23:02:28 +0300 Subject: [PATCH] CPP-5040: Separate macro expansion for parameters and for files/dirs This fixes "quoted strings" sneaking into input redirection file and working directory values when a macro used there expands to a value requiring quoting, for example, a path containing spaces. GitOrigin-RevId: 125f3e3436e8c6982fa7ddccac23f4300b2b11ea --- .../execution/util/JavaParametersUtil.java | 7 ++-- .../util/ProgramParametersConfigurator.java | 40 +++++++++++++++---- .../run/PythonScriptCommandLineState.java | 20 +++++----- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java index ecb9c44c6668..c87196525dad 100644 --- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java +++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.execution.util; import com.intellij.execution.CantRunException; @@ -56,10 +56,9 @@ public class JavaParametersUtil { for (Map.Entry each : parameters.getEnv().entrySet()) { vmParameters = StringUtil.replace(vmParameters, "$" + each.getKey() + "$", each.getValue(), false); //replace env usages } - vmParameters = ProgramParametersConfigurator.expandMacros(vmParameters); + List vmParametersList = ProgramParametersConfigurator.expandMacrosAndParseParameters(vmParameters); + parameters.getVMParametersList().addAll(vmParametersList); } - - parameters.getVMParametersList().addParametersString(vmParameters); } @MagicConstant(valuesFromClass = JavaParameters.class) diff --git a/platform/execution-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java b/platform/execution-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java index 80bc61917732..ae031d25fca1 100644 --- a/platform/execution-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java +++ b/platform/execution-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java @@ -25,13 +25,16 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.EnvironmentUtil; import com.intellij.util.PathUtil; import com.intellij.util.execution.ParametersListUtil; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.SystemIndependent; import org.jetbrains.jps.model.serialization.PathMacroUtil; import java.io.File; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; public class ProgramParametersConfigurator { @@ -60,10 +63,11 @@ public class ProgramParametersConfigurator { parameters.setPassParentEnvs(configuration.isPassParentEnvs()); } - @Nullable - public String expandPathAndMacros(String s, Module module, Project project) { - return expandMacros(expandPath(s, module, project), - projectContext(project, module)); + @Contract("!null, _, _ -> !null") + public @Nullable String expandPathAndMacros(String s, Module module, Project project) { + final String path = expandPath(s, module, project); + if (path == null) return null; + return expandMacros(path, projectContext(project, module), false); } private static @NotNull DataContext projectContext(Project project, Module module) { @@ -74,12 +78,30 @@ public class ProgramParametersConfigurator { }; } + /** + * Unless expanding macros in a generic value that doesn't represent a path of some kind, or a parameter string, + * consider using the following specialized methods instead: + * + * @see #expandMacrosAndParseParameters For values representing parameters: program arguments, VM options + * @see #expandPathAndMacros For paths: working directory, input file, etc. + */ public static String expandMacros(@Nullable String path) { - return expandMacros(path, DataContext.EMPTY_CONTEXT); + if (StringUtil.isEmpty(path)) { + return path; + } + return expandMacros(path, DataContext.EMPTY_CONTEXT, false); } - protected static String expandMacros(@Nullable String path, @NotNull DataContext dataContext) { - if (path == null || !Registry.is("allow.macros.for.run.configurations")) { + public static @NotNull List expandMacrosAndParseParameters(@Nullable String parametersStringWithMacros) { + if (StringUtil.isEmpty(parametersStringWithMacros)) { + return Collections.emptyList(); + } + final String expandedParametersString = expandMacros(parametersStringWithMacros, DataContext.EMPTY_CONTEXT, true); + return ParametersListUtil.parse(expandedParametersString); + } + + private static @NotNull String expandMacros(@NotNull String path, @NotNull DataContext dataContext, boolean applyParameterEscaping) { + if (!Registry.is("allow.macros.for.run.configurations")) { return path; } @@ -89,7 +111,9 @@ public class ProgramParametersConfigurator { index != -1 && index < path.length() + template.length(); index = path.indexOf(template, index)) { String value = StringUtil.notNullize(previewOrExpandMacro(macro, dataContext)); - value = ParametersListUtil.escape(value); + if (applyParameterEscaping) { + value = ParametersListUtil.escape(value); + } path = path.substring(0, index) + value + path.substring(index + template.length()); //noinspection AssignmentToForLoopParameter index += value.length(); diff --git a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java index a51186157dd2..bae350a66905 100644 --- a/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java +++ b/python/src/com/jetbrains/python/run/PythonScriptCommandLineState.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.python.run; import com.intellij.execution.DefaultExecutionResult; @@ -41,6 +41,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.util.List; import java.util.Map; /** @@ -226,8 +227,7 @@ public class PythonScriptCommandLineState extends PythonCommandLineState { } } - final String scriptOptionsString = getExpandedScriptParameters(); - if (scriptOptionsString != null) scriptParameters.addParametersString(scriptOptionsString); + scriptParameters.addParameters(getExpandedScriptParameters()); if (!StringUtil.isEmptyOrSpaces(myConfig.getWorkingDirectory())) { commandLine.setWorkDirectory(myConfig.getWorkingDirectory()); @@ -238,10 +238,9 @@ public class PythonScriptCommandLineState extends PythonCommandLineState { } } - @Nullable - private String getExpandedScriptParameters() { + private @NotNull List getExpandedScriptParameters() { final String parameters = myConfig.getScriptParameters(); - return ProgramParametersConfigurator.expandMacros(parameters); + return ProgramParametersConfigurator.expandMacrosAndParseParameters(parameters); } private static String escape(String s) { @@ -273,15 +272,14 @@ public class PythonScriptCommandLineState extends PythonCommandLineState { sb.append("runfile('").append(escape(scriptPath)).append("'"); - final String parametersString = getExpandedScriptParameters(); - final String[] scriptParameters = parametersString != null ? ParametersList.parse(parametersString) : ArrayUtil.EMPTY_STRING_ARRAY; - if (scriptParameters.length != 0) { + final List scriptParameters = getExpandedScriptParameters(); + if (scriptParameters.size() != 0) { sb.append(", args=["); - for (int i = 0; i < scriptParameters.length; i++) { + for (int i = 0; i < scriptParameters.size(); i++) { if (i != 0) { sb.append(", "); } - sb.append("'").append(escape(scriptParameters[i])).append("'"); + sb.append("'").append(escape(scriptParameters.get(i))).append("'"); } sb.append("]"); }