summaryrefslogtreecommitdiffhomepage
path: root/test/syscalls
diff options
context:
space:
mode:
authorAndrei Vagin <avagin@google.com>2020-05-04 12:57:04 -0700
committergVisor bot <gvisor-bot@google.com>2020-05-04 12:58:24 -0700
commit006f9788291359fc871b2fa7b82338912af7abb7 (patch)
tree3e3eb4a61607c27228796908eb7e78f0c6a21317 /test/syscalls
parent660a1a10283ba1c11398280fecff588d97743584 (diff)
Deflake //third_party/gvisor/test/syscalls:proc_test_native
There is the known issue of the linux procfs, that two consequent calls of readdir can return the same entry twice if between these calls one or more entries have been removed from this directory. PiperOrigin-RevId: 309803066
Diffstat (limited to 'test/syscalls')
-rw-r--r--test/syscalls/linux/proc.cc89
1 files changed, 56 insertions, 33 deletions
diff --git a/test/syscalls/linux/proc.cc b/test/syscalls/linux/proc.cc
index 79a625ebc..63642880a 100644
--- a/test/syscalls/linux/proc.cc
+++ b/test/syscalls/linux/proc.cc
@@ -1939,43 +1939,66 @@ TEST(ProcSelfMounts, RequiredFieldsArePresent) {
}
void CheckDuplicatesRecursively(std::string path) {
- errno = 0;
- DIR* dir = opendir(path.c_str());
- if (dir == nullptr) {
- // Ignore any directories we can't read or missing directories as the
- // directory could have been deleted/mutated from the time the parent
- // directory contents were read.
- return;
- }
- auto dir_closer = Cleanup([&dir]() { closedir(dir); });
- std::unordered_set<std::string> children;
- while (true) {
- // Readdir(3): If the end of the directory stream is reached, NULL is
- // returned and errno is not changed. If an error occurs, NULL is returned
- // and errno is set appropriately. To distinguish end of stream and from an
- // error, set errno to zero before calling readdir() and then check the
- // value of errno if NULL is returned.
+ std::vector<std::string> child_dirs;
+
+ // There is the known issue of the linux procfs, that two consequent calls of
+ // readdir can return the same entry twice if between these calls one or more
+ // entries have been removed from this directory.
+ int max_attempts = 5;
+ for (int i = 0; i < max_attempts; i++) {
+ child_dirs.clear();
errno = 0;
- struct dirent* dp = readdir(dir);
- if (dp == nullptr) {
- ASSERT_EQ(errno, 0) << path;
- break; // We're done.
+ bool success = true;
+ DIR* dir = opendir(path.c_str());
+ if (dir == nullptr) {
+ // Ignore any directories we can't read or missing directories as the
+ // directory could have been deleted/mutated from the time the parent
+ // directory contents were read.
+ return;
}
-
- if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
- continue;
+ auto dir_closer = Cleanup([&dir]() { closedir(dir); });
+ std::unordered_set<std::string> children;
+ while (true) {
+ // Readdir(3): If the end of the directory stream is reached, NULL is
+ // returned and errno is not changed. If an error occurs, NULL is
+ // returned and errno is set appropriately. To distinguish end of stream
+ // and from an error, set errno to zero before calling readdir() and then
+ // check the value of errno if NULL is returned.
+ errno = 0;
+ struct dirent* dp = readdir(dir);
+ if (dp == nullptr) {
+ ASSERT_EQ(errno, 0) << path;
+ break; // We're done.
+ }
+
+ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
+ continue;
+ }
+
+ // Ignore a duplicate entry if it isn't the last attempt.
+ if (i == max_attempts - 1) {
+ ASSERT_EQ(children.find(std::string(dp->d_name)), children.end())
+ << absl::StrCat(path, "/", dp->d_name);
+ } else if (children.find(std::string(dp->d_name)) != children.end()) {
+ std::cerr << "Duplicate entry: " << i << ":"
+ << absl::StrCat(path, "/", dp->d_name) << std::endl;
+ success = false;
+ break;
+ }
+ children.insert(std::string(dp->d_name));
+
+ ASSERT_NE(dp->d_type, DT_UNKNOWN);
+
+ if (dp->d_type == DT_DIR) {
+ child_dirs.push_back(std::string(dp->d_name));
+ }
}
-
- ASSERT_EQ(children.find(std::string(dp->d_name)), children.end())
- << dp->d_name;
- children.insert(std::string(dp->d_name));
-
- ASSERT_NE(dp->d_type, DT_UNKNOWN);
-
- if (dp->d_type != DT_DIR) {
- continue;
+ if (success) {
+ break;
}
- CheckDuplicatesRecursively(absl::StrCat(path, "/", dp->d_name));
+ }
+ for (auto dname = child_dirs.begin(); dname != child_dirs.end(); dname++) {
+ CheckDuplicatesRecursively(absl::StrCat(path, "/", *dname));
}
}