From f6eb5daa16368fb90d5a59b14a72bfd8ddbcd2a0 Mon Sep 17 00:00:00 2001 From: Andrew Ng Date: Mon, 13 Jul 2020 13:36:33 +0100 Subject: [PATCH] [Support] Fix Windows directory_iterator_construct out of bounds Fix incorrect use of the size of Path when accessing PathUTF16, as the UTF-16 path can be shorter. Added unit test for coverage of this test case. Thanks to Ding Fei (danix800) for the code fix, see https://reviews.llvm.org/D83321. Differential Revision: https://reviews.llvm.org/D83689 --- llvm/lib/Support/Windows/Path.inc | 6 +++--- llvm/unittests/Support/Path.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index 399a0cc..e352beb 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -957,9 +957,9 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &IT, return EC; // Convert path to the format that Windows is happy with. - if (PathUTF16.size() > 0 && - !is_separator(PathUTF16[Path.size() - 1]) && - PathUTF16[Path.size() - 1] != L':') { + size_t PathUTF16Len = PathUTF16.size(); + if (PathUTF16Len > 0 && !is_separator(PathUTF16[PathUTF16Len - 1]) && + PathUTF16[PathUTF16Len - 1] != L':') { PathUTF16.push_back(L'\\'); PathUTF16.push_back(L'*'); } else { diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index 6a228f0..19ff49d 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1149,6 +1149,39 @@ TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) { } #endif +#ifdef _WIN32 +TEST_F(FileSystemTest, UTF8ToUTF16DirectoryIteration) { + // The Windows filesystem support uses UTF-16 and converts paths from the + // input UTF-8. The UTF-16 equivalent of the input path can be shorter in + // length. + + // This test relies on TestDirectory not being so long such that MAX_PATH + // would be exceeded (see widenPath). If that were the case, the UTF-16 + // path is likely to be longer than the input. + const char *Pi = "\xcf\x80"; // UTF-8 lower case pi. + std::string RootDir = (TestDirectory + "/" + Pi).str(); + + // Create test directories. + ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/a")); + ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/b")); + + std::error_code EC; + unsigned Count = 0; + for (fs::directory_iterator I(Twine(RootDir), EC), E; I != E; + I.increment(EC)) { + ASSERT_NO_ERROR(EC); + StringRef DirName = path::filename(I->path()); + EXPECT_TRUE(DirName == "a" || DirName == "b"); + ++Count; + } + EXPECT_EQ(Count, 2U); + + ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/a")); + ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/b")); + ASSERT_NO_ERROR(fs::remove(Twine(RootDir))); +} +#endif + TEST_F(FileSystemTest, Remove) { SmallString<64> BaseDir; SmallString<64> Paths[4]; -- 2.7.4