Utils: Fix operator escaping

Stops CommandLine / ProcessArgs from escaping
operators '&&', '||' and ';'.

Fixes: QTCREATORBUG-29280
Change-Id: Idf4f429fec0d96b67266761297eea851c283ac4c
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Marcus Tillmanns
2023-06-15 08:20:56 +02:00
parent 8aff1dfd85
commit 6c34e1937c
2 changed files with 88 additions and 4 deletions

View File

@@ -514,6 +514,9 @@ QString ProcessArgs::quoteArgUnix(const QString &arg)
QString ret(arg); QString ret(arg);
if (hasSpecialCharsUnix(ret)) { if (hasSpecialCharsUnix(ret)) {
if (arg == "&&" || arg == "||" || arg == "&" || arg == ';')
return ret;
ret.replace(QLatin1Char('\''), QLatin1String("'\\''")); ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
ret.prepend(QLatin1Char('\'')); ret.prepend(QLatin1Char('\''));
ret.append(QLatin1Char('\'')); ret.append(QLatin1Char('\''));
@@ -550,6 +553,9 @@ static QString quoteArgWin(const QString &arg)
QString ret(arg); QString ret(arg);
if (hasSpecialCharsWin(ret)) { if (hasSpecialCharsWin(ret)) {
if (arg == "&&" || arg == "||" || arg == "&" || arg == ';')
return ret;
// Quotes are escaped and their preceding backslashes are doubled. // Quotes are escaped and their preceding backslashes are doubled.
// It's impossible to escape anything inside a quoted string on cmd // It's impossible to escape anything inside a quoted string on cmd
// level, so the outer quoting must be "suspended". // level, so the outer quoting must be "suspended".

View File

@@ -188,17 +188,95 @@ private slots:
QCOMPARE(cmd.arguments(), "and args"); QCOMPARE(cmd.arguments(), "and args");
} }
void testFromInputWithMacro_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("expectedExecutable");
QTest::addColumn<QString>("expectedArguments");
QTest::newRow("simple") << "command %{hello}"
<< "command"
<< (HostOsInfo::isWindowsHost() ? "\"hello world\""
: "'hello world'");
QTest::newRow("simple-quoted")
<< "command \"%{hello}\""
<< "command" << (HostOsInfo::isWindowsHost() ? "\"hello world\"" : "'hello world'");
QTest::newRow("quoted-with-extra")
<< "command \"%{hello}, he said\""
<< "command"
<< (HostOsInfo::isWindowsHost() ? "\"hello world, he said\"" : "'hello world, he said'");
QTest::newRow("convert-to-quote-win")
<< "command 'this is a test'"
<< "command"
<< (HostOsInfo::isWindowsHost() ? "\"this is a test\"" : "'this is a test'");
}
void testFromInputWithMacro() void testFromInputWithMacro()
{ {
QFETCH(QString, input);
QFETCH(QString, expectedExecutable);
QFETCH(QString, expectedArguments);
MacroExpander expander; MacroExpander expander;
expander.registerVariable("hello", "world var", [] { return "hello world"; }); expander.registerVariable("hello", "world var", [] { return "hello world"; });
CommandLine cmd = CommandLine::fromUserInput("command macroarg: %{hello}", &expander);
QCOMPARE(cmd.executable(), "command");
CommandLine cmd = CommandLine::fromUserInput(input, &expander);
QCOMPARE(cmd.executable().toUserOutput(), expectedExecutable);
// TODO: Fix (macro) escaping on windows
if (HostOsInfo::isWindowsHost()) if (HostOsInfo::isWindowsHost())
QEXPECT_FAIL("", "Windows does not correctly quote macro arguments", Continue); QEXPECT_FAIL("simple", "Windows does not correctly quote macro arguments", Continue);
if (HostOsInfo::isWindowsHost())
QEXPECT_FAIL("simple-quoted", "Windows removes quotes from macro arguments", Continue);
if (HostOsInfo::isWindowsHost())
QEXPECT_FAIL("convert-to-quote-win",
"Windows should convert single to double quotes",
Continue);
QCOMPARE(cmd.arguments(), "macroarg: 'hello world'"); QCOMPARE(cmd.arguments(), expectedArguments);
}
void testMultiCommand_data()
{
QTest::addColumn<QString>("input");
QTest::addColumn<QString>("executable");
QTest::addColumn<QString>("arguments");
QTest::newRow("command-and-command") << "command1 && command2"
<< "command1"
<< "&& command2";
QTest::newRow("command-and-command-nospace") << "command1&&command2"
<< "command1"
<< "&&command2";
QTest::newRow("command-semicolon-command") << "command1 ; command2"
<< "command1"
<< "; command2";
QTest::newRow("command-or-command") << "command1 || command2"
<< "command1"
<< "|| command2";
}
void testMultiCommand()
{
QFETCH(QString, input);
QFETCH(QString, executable);
QFETCH(QString, arguments);
CommandLine cmdLine = CommandLine::fromUserInput(input);
QEXPECT_FAIL(
"command-and-command-nospace",
"CommandLine::fromUserInput does not handle multi-command without space correctly",
Abort);
QCOMPARE(cmdLine.executable().path(), executable);
QCOMPARE(cmdLine.arguments(), arguments);
} }
}; };