Escape process names and command lines (add support for command lines with a line break, related to RIDER-34308)

GitOrigin-RevId: a92723006a0aef95c999c115d23f40e5a4f6ae14
This commit is contained in:
Vyacheslav Moklev
2019-11-25 10:08:24 +00:00
committed by intellij-monorepo-bot
parent 314b85ea95
commit ace80507fb
2 changed files with 77 additions and 7 deletions
@@ -4,9 +4,29 @@
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#include <string>
#pragma comment(lib, "wbemuuid.lib")
void stringReplaceAll(wstring& str, const wstring& oldStr, const wstring& newStr)
{
int pos = 0;
while ((pos = str.find(oldStr, pos)) != string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
wstring escapeLineBreaks(const wstring& str)
{
wstring result = str;
stringReplaceAll(result, L"\\", L"\\\\");
stringReplaceAll(result, L"\n", L"\\n");
stringReplaceAll(result, L"\r", L"\\r");
return result;
}
int main(int argc, char **argv)
{
HRESULT hres;
@@ -163,19 +183,19 @@ int main(int argc, char **argv)
VARIANT vtId;
pclsObj->Get(L"ProcessId", 0, &vtId, nullptr, nullptr);
wprintf_s(L"%d\n", vtId.intVal);
wcout << vtId.intVal << "\n";
VARIANT vtName;
pclsObj->Get(L"Name", 0, &vtName, nullptr, nullptr);
if (vtName.bstrVal != nullptr)
wprintf_s(L"%ls\n", vtName.bstrVal);
wcout << escapeLineBreaks(vtName.bstrVal) << L"\n";
else
wprintf_s(L"\n");
wcout << L"\n";
VARIANT vtCmd;
pclsObj->Get(L"CommandLine", 0, &vtCmd, nullptr, nullptr);
if (vtCmd.bstrVal != nullptr)
wprintf_s(L"%ls\n", vtCmd.bstrVal);
wcout << L"\"" << escapeLineBreaks(vtCmd.bstrVal) << L"\"\n";
else
wprintf_s(L"\n");
wcout << L"\"\"\n";
VariantClear(&vtId);
VariantClear(&vtName);
VariantClear(&vtCmd);
@@ -266,6 +266,46 @@ public final class ProcessListUtil {
return parseCommandOutput(Collections.singletonList(exeFile.getAbsolutePath()), ProcessListUtil::parseWinProcessListHelperOutput);
}
@Nullable
private static String unescapeString(String str, boolean quoted) {
StringBuilder builder = new StringBuilder();
if (quoted) {
str = str.substring(1, str.length() - 1);
}
for (int index = 0; index < str.length(); index++) {
if (str.charAt(index) == '\\') {
if (index == str.length() - 1) {
LOG.info("Invalid escaped string: backslash at the last position");
LOG.debug(str);
return null;
}
switch (str.charAt(index + 1)) {
case '\\': {
builder.append('\\');
break;
}
case 'n': {
builder.append('\n');
break;
}
case 'r': {
builder.append('\r');
break;
}
default: {
LOG.info("Invalid character after an escape symbol: " + str.charAt(index + 1));
LOG.debug(str);
return null;
}
}
index++;
continue;
}
builder.append(str.charAt(index));
}
return builder.toString();
}
@Nullable
static List<ProcessInfo> parseWinProcessListHelperOutput(@NotNull String output) {
String[] lines = StringUtil.splitByLines(output, false);
@@ -286,10 +326,20 @@ public final class ProcessListUtil {
}
if (id == 0) continue;
String name = lines[offset + 1];
String name = unescapeString(lines[offset + 1], false);
if (name == null) {
LOG.info("Invalid escaped name: " + lines[offset + 1]);
LOG.debug(output);
return null;
}
if (StringUtil.isEmpty(name)) continue;
String commandLine = lines[offset + 2];
String commandLine = unescapeString(lines[offset + 2], true);
if (commandLine == null) {
LOG.info("Invalid escaped command line: " + lines[offset + 2]);
LOG.debug(output);
return null;
}
String args;
if (commandLine.isEmpty()) {
commandLine = name;