diff options
author | Andrei Vagin <avagin@google.com> | 2020-05-04 12:57:04 -0700 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2020-05-04 12:58:24 -0700 |
commit | 006f9788291359fc871b2fa7b82338912af7abb7 (patch) | |
tree | 3e3eb4a61607c27228796908eb7e78f0c6a21317 /test | |
parent | 660a1a10283ba1c11398280fecff588d97743584 (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')
-rw-r--r-- | test/syscalls/linux/proc.cc | 89 |
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)); } } |