From f1b460f9ea35039296905b25cd6871f99b05652a Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Tue, 20 May 2014 22:12:58 +0000 Subject: [PATCH] VirtualFileSystem: Fix false positives in YAMLVFSWriter::containedIn Checking if a path starts with another path isn't sufficient for determining if one is contained within the heirarchy of the other. We need to ensure that the substring ends at a directory boundary. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209250 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Basic/VirtualFileSystem.cpp | 11 ++++++- unittests/libclang/LibclangTest.cpp | 51 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index 24454b0192..077370dcf4 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/lib/Basic/VirtualFileSystem.cpp @@ -928,7 +928,16 @@ YAMLVFSWriter::printContents(llvm::raw_ostream &OS, ArrayRef Entries, } bool YAMLVFSWriter::containedIn(StringRef Parent, StringRef Path) { - return Path.startswith(Parent); + using namespace llvm::sys; + // Compare each path component. + auto IParent = path::begin(Parent), EParent = path::end(Parent); + for (auto IChild = path::begin(Path), EChild = path::end(Path); + IParent != EParent && IChild != EChild; ++IParent, ++IChild) { + if (*IParent != *IChild) + return false; + } + // Have we exhausted the parent path? + return IParent == EParent; } StringRef YAMLVFSWriter::containedPart(StringRef Parent, StringRef Path) { diff --git a/unittests/libclang/LibclangTest.cpp b/unittests/libclang/LibclangTest.cpp index 50d4c489f2..61578a4801 100644 --- a/unittests/libclang/LibclangTest.cpp +++ b/unittests/libclang/LibclangTest.cpp @@ -184,6 +184,57 @@ TEST(libclang, VirtualFileOverlay) { T.map("/path/virtual/foo.h", "/real/foo.h"); clang_VirtualFileOverlay_setCaseSensitivity(T.VFO, false); } + { + const char *contents = + "{\n" + " 'version': 0,\n" + " 'roots': [\n" + " {\n" + " 'type': 'directory',\n" + " 'name': \"/path/foo\",\n" + " 'contents': [\n" + " {\n" + " 'type': 'file',\n" + " 'name': \"bar\",\n" + " 'external-contents': \"/real/bar\"\n" + " },\n" + " {\n" + " 'type': 'file',\n" + " 'name': \"bar.h\",\n" + " 'external-contents': \"/real/bar.h\"\n" + " }\n" + " ]\n" + " },\n" + " {\n" + " 'type': 'directory',\n" + " 'name': \"/path/foobar\",\n" + " 'contents': [\n" + " {\n" + " 'type': 'file',\n" + " 'name': \"baz.h\",\n" + " 'external-contents': \"/real/baz.h\"\n" + " }\n" + " ]\n" + " },\n" + " {\n" + " 'type': 'directory',\n" + " 'name': \"/path\",\n" + " 'contents': [\n" + " {\n" + " 'type': 'file',\n" + " 'name': \"foobarbaz.h\",\n" + " 'external-contents': \"/real/foobarbaz.h\"\n" + " }\n" + " ]\n" + " }\n" + " ]\n" + "}\n"; + TestVFO T(contents); + T.map("/path/foo/bar.h", "/real/bar.h"); + T.map("/path/foo/bar", "/real/bar"); + T.map("/path/foobar/baz.h", "/real/baz.h"); + T.map("/path/foobarbaz.h", "/real/foobarbaz.h"); + } } TEST(libclang, ModuleMapDescriptor) { -- 2.40.0