Fix /proc/*/stat parsing in GVisor

The code in GVisor relied on the process name not containing whitespace when
parsing /proc/*/stat. This CL fixes that by moving parsing to its own function,
implemented properly.

PiperOrigin-RevId: 511616209
This commit is contained in:
gVisor bot
2023-02-22 15:43:14 -08:00
parent 442b16ee24
commit d94ff26acc
2 changed files with 26 additions and 2 deletions
+1
View File
@@ -1820,6 +1820,7 @@ cc_binary(
"//test/util:file_descriptor",
"//test/util:fs_util",
"//test/util:mount_util",
"@com_google_absl//absl/algorithm:container",
"@com_google_absl//absl/container:node_hash_set",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
+25 -2
View File
@@ -37,6 +37,7 @@
#include <atomic>
#include <functional>
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <ostream>
@@ -48,6 +49,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/algorithm/container.h"
#include "absl/container/node_hash_set.h"
#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
@@ -1483,12 +1485,32 @@ TEST(ProcLoadavg, Fields) {
class ProcPidStatTest : public ::testing::TestWithParam<std::string> {};
// Parses /proc/<pid>/stat output to a vector of string. We need a more
// complicated approach than absl::StrSplit because COMM can contain spaces.
PosixErrorOr<std::vector<std::string>> ParseProcPidStat(
absl::string_view proc_pid_stat) {
auto comm_start = proc_pid_stat.find('(');
auto comm_end = proc_pid_stat.rfind(')');
if (comm_start == proc_pid_stat.npos || comm_end == proc_pid_stat.npos) {
return PosixError(EINVAL, absl::StrCat("Invalid /proc/<pid>/stat"));
}
std::vector<std::string> fields =
absl::StrSplit(proc_pid_stat.substr(0, comm_start - 1), ' ');
fields.push_back(std::string{proc_pid_stat.substr(comm_start, comm_end + 1)});
absl::c_transform(absl::StrSplit(proc_pid_stat.substr(comm_end + 2), ' '),
std::back_inserter(fields),
[](auto sv) { return std::string{sv}; });
return fields;
}
TEST_P(ProcPidStatTest, HasBasicFields) {
std::string proc_pid_stat = ASSERT_NO_ERRNO_AND_VALUE(
GetContents(absl::StrCat("/proc/", GetParam(), "/stat")));
ASSERT_FALSE(proc_pid_stat.empty());
std::vector<std::string> fields = absl::StrSplit(proc_pid_stat, ' ');
std::vector<std::string> fields =
ASSERT_NO_ERRNO_AND_VALUE(ParseProcPidStat(proc_pid_stat));
ASSERT_GE(fields.size(), 24);
EXPECT_EQ(absl::StrCat(getpid()), fields[0]);
// fields[1] is the thread name.
@@ -1546,7 +1568,8 @@ PosixErrorOr<uint64_t> CurrentRSS() {
return PosixError(EINVAL, "empty /proc/self/stat");
}
std::vector<std::string> fields = absl::StrSplit(proc_self_stat, ' ');
ASSIGN_OR_RETURN_ERRNO(std::vector<std::string> fields,
ParseProcPidStat(proc_self_stat));
if (fields.size() < 24) {
return PosixError(
EINVAL,