1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2019 Luxoft Sweden AB
// Copyright (C) 2018 Pelagicore AG
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:critical reason:data-parser
#include "debugwrapper.h"
using namespace Qt::StringLiterals;
QT_BEGIN_NAMESPACE_AM
namespace DebugWrapper {
bool parseSpecification(const QString &debugWrapperSpecification, QStringList &resultingCommand,
QMap<QString, QString> &resultingEnvironment)
{
QStringList cmd;
QMap<QString, QString> env;
// split at ' ', but also accept escape sequences for '\ ', '\n' and '\\'
// all leading FOO=BAR args will be converted to env var assignments
bool escaped = false;
bool canBeEnvVar = true;
bool isEnvVar = false;
static const QString program = u"%program%"_s;
static const QString arguments = u"%arguments%"_s;
int foundProgram = 0;
int foundArguments = 0;
QString str;
QString value;
QString *current = &str;
qsizetype size = debugWrapperSpecification.size();
for (qsizetype i = 0; i <= size; ++i) {
const QChar c = (i < size) ? debugWrapperSpecification.at(i) : QChar(0);
if (!escaped || c.isNull()) {
switch (c.unicode()) {
case '\\':
escaped = true;
break;
case '=':
// switch to value parsing if this can be an env var and if this is the first =
// all other = are copied verbatim
isEnvVar = canBeEnvVar;
if (isEnvVar && current == &str)
current = &value;
else
current->append(u'=');
break;
case ' ':
case '\0':
// found the end of an argument: add to env vars or cmd and reset state
if (!str.isEmpty()) {
if (isEnvVar) {
env.insert(str, value);
} else {
cmd.append(str);
foundArguments = foundArguments || str.contains(arguments);
foundProgram = foundProgram || str.contains(program);
}
}
canBeEnvVar = isEnvVar; // stop parsing as envvar as soon as we get a normal arg
isEnvVar = false;
current = &str;
str.clear();
value.clear();
break;
default:
current->append(c);
break;
}
} else {
switch (c.unicode()) {
case '\\': current->append(u'\\'); break;
case ' ': current->append(u' '); break;
case 'n': current->append(u'\n'); break;
default: return false;
}
escaped = false;
}
}
if (cmd.isEmpty() && env.isEmpty())
return false;
// convenience: if the spec doesn't include %program% or %arguments%, then simply append them
if (!foundProgram)
cmd << program;
if (!foundArguments)
cmd << arguments;
resultingCommand = cmd;
resultingEnvironment = env;
return true;
}
QStringList substituteCommand(const QStringList &debugWrapperCommand, const QString &program,
const QStringList &arguments)
{
QString stringifiedArguments = arguments.join(u' ');
QStringList result;
for (const QString &s : debugWrapperCommand) {
if (s == u"%arguments%") {
result << arguments;
} else {
QString str(s);
str.replace(u"%program%"_s, program);
str.replace(u"%arguments%"_s, stringifiedArguments);
result << str;
}
}
return result;
}
} // namespace DebugWrapper
QT_END_NAMESPACE_AM
|