RemoteLinux: Make remote process PID parsing more robust

- Do not assume that the PID string is the first output.
- Do not assume output has already been read when the process finishes.

Fixes: QTCREATORBUG-25306
Change-Id: Ia7cec6113e7f86469da2e6e0c62e08b38213093a
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Christian Kandeler
2021-02-08 12:10:32 +01:00
parent 058841e8de
commit 30d4f7b48c
2 changed files with 28 additions and 16 deletions

View File

@@ -34,15 +34,18 @@ using namespace Utils;
namespace RemoteLinux { namespace RemoteLinux {
const QByteArray pidMarker = "__qtc";
LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer<const ProjectExplorer::IDevice> &device, LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer<const ProjectExplorer::IDevice> &device,
QObject *parent) QObject *parent)
: ProjectExplorer::SshDeviceProcess(device, parent), m_processId(0) : ProjectExplorer::SshDeviceProcess(device, parent)
{ {
connect(this, &DeviceProcess::finished, this, [this]() { connect(this, &DeviceProcess::finished, this, [this]() {
m_processId = -1; m_processId = 0;
}); });
connect(this, &DeviceProcess::started, this, [this]() { connect(this, &DeviceProcess::started, this, [this]() {
m_processId = 0; m_pidParsed = false;
m_output.clear();
}); });
} }
@@ -54,18 +57,26 @@ void LinuxDeviceProcess::setRcFilesToSource(const QStringList &filePaths)
QByteArray LinuxDeviceProcess::readAllStandardOutput() QByteArray LinuxDeviceProcess::readAllStandardOutput()
{ {
QByteArray output = SshDeviceProcess::readAllStandardOutput(); QByteArray output = SshDeviceProcess::readAllStandardOutput();
if (m_processId != 0 || runInTerminal()) if (m_pidParsed || runInTerminal())
return output; return output;
m_processIdString.append(output); m_output.append(output);
int cut = m_processIdString.indexOf('\n'); static const QByteArray endMarker = pidMarker + '\n';
if (cut != -1) { const int endMarkerOffset = m_output.indexOf(endMarker);
m_processId = m_processIdString.left(cut).toLongLong(); if (endMarkerOffset == -1)
output = m_processIdString.mid(cut + 1); return {};
m_processIdString.clear(); const int startMarkerOffset = m_output.indexOf(pidMarker);
return output; if (startMarkerOffset == endMarkerOffset) // Only theoretically possible.
} return {};
return QByteArray(); const int pidStart = startMarkerOffset + pidMarker.length();
const QByteArray pidString = m_output.mid(pidStart, endMarkerOffset - pidStart);
m_pidParsed = true;
m_processId = pidString.toLongLong();
// We don't want to show output from e.g. /etc/profile.
const QByteArray actualOutput = m_output.mid(endMarkerOffset + endMarker.length());
m_output.clear();
return actualOutput;
} }
qint64 LinuxDeviceProcess::processId() const qint64 LinuxDeviceProcess::processId() const
@@ -90,7 +101,7 @@ QString LinuxDeviceProcess::fullCommandLine(const Runnable &runnable) const
} }
if (!runInTerminal()) if (!runInTerminal())
cmd.addArgs("echo $$ && ", CommandLine::Raw); cmd.addArgs(QString("echo ") + pidMarker + "$$" + pidMarker + " && ", CommandLine::Raw);
const Environment &env = runnable.environment; const Environment &env = runnable.environment;
for (auto it = env.constBegin(); it != env.constEnd(); ++it) for (auto it = env.constBegin(); it != env.constEnd(); ++it)

View File

@@ -52,8 +52,9 @@ private:
const QStringList rcFilesToSource() const; const QStringList rcFilesToSource() const;
QStringList m_rcFilesToSource; QStringList m_rcFilesToSource;
QByteArray m_processIdString; QByteArray m_output;
qint64 m_processId; qint64 m_processId = 0;
bool m_pidParsed = false;
}; };
} // namespace RemoteLinux } // namespace RemoteLinux