|
16 | 16 |
|
17 | 17 | #include <sys/stat.h> |
18 | 18 | #include <sys/types.h> |
| 19 | +#include <unistd.h> |
19 | 20 |
|
| 21 | +#include <cerrno> |
20 | 22 | #include <cstdlib> |
| 23 | +#include <cstring> |
21 | 24 | #include <functional> |
22 | 25 | #include <string> |
23 | 26 | #include <vector> |
@@ -113,6 +116,31 @@ TEST(YieldFilesTest, YieldsHiddenFilesAndDirs) { |
113 | 116 | EXPECT_THAT(collected_paths, testing::SizeIs(2)); |
114 | 117 | } |
115 | 118 |
|
| 119 | +TEST(YieldFilesTest, DoesNotRecurseThroughSymlinkLoop) { |
| 120 | + const std::string root_dir = |
| 121 | + absl::StrCat(getenv("TEST_TMPDIR"), "/symlink-loop-root"); |
| 122 | + ASSERT_EQ(mkdir(root_dir.c_str(), 0755), 0); |
| 123 | + const std::string dir_a = absl::StrCat(root_dir, "/dirA"); |
| 124 | + ASSERT_EQ(mkdir(dir_a.c_str(), 0755), 0); |
| 125 | + const std::string dir_b = absl::StrCat(root_dir, "/dirB"); |
| 126 | + ASSERT_EQ(mkdir(dir_b.c_str(), 0755), 0); |
| 127 | + |
| 128 | + const std::string link_to_b = absl::StrCat(dir_a, "/toB"); |
| 129 | + if (symlink(dir_b.c_str(), link_to_b.c_str()) != 0) { |
| 130 | + GTEST_SKIP() << "symlink unsupported in this environment: " |
| 131 | + << std::strerror(errno); |
| 132 | + } |
| 133 | + const std::string link_to_a = absl::StrCat(dir_b, "/toA"); |
| 134 | + ASSERT_EQ(symlink(dir_a.c_str(), link_to_a.c_str()), 0); |
| 135 | + |
| 136 | + std::vector<std::string> collected_paths; |
| 137 | + const absl::Status status = |
| 138 | + YieldFiles(root_dir, CollectPathsCallback(&collected_paths)); |
| 139 | + EXPECT_TRUE(status.ok()); |
| 140 | + EXPECT_GT(collected_paths.size(), 0); |
| 141 | + EXPECT_LE(collected_paths.size(), 6); |
| 142 | +} |
| 143 | + |
116 | 144 | } // namespace |
117 | 145 |
|
118 | 146 | } // namespace fuzzing |
0 commit comments