aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Basic/VirtualFileSystem.cpp
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2016-03-16 04:39:38 +0000
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>2016-03-16 04:39:38 +0000
commitc9daaaedb67e1e0265f795f8a9cbad6bc9553883 (patch)
treec74b0275504b2e8b50bbcd69da6032249894f0b0 /clang/lib/Basic/VirtualFileSystem.cpp
parent7865b2e9439839cdb354cae848038def79826796 (diff)
downloadllvm-c9daaaedb67e1e0265f795f8a9cbad6bc9553883.zip
llvm-c9daaaedb67e1e0265f795f8a9cbad6bc9553883.tar.gz
llvm-c9daaaedb67e1e0265f795f8a9cbad6bc9553883.tar.bz2
Reapply: [VFS] Add support for handling path traversals
This is originally r261551, reverted because of windows bots failing on unittests. Change the current behavior to do not handle path traversals on windows. Handle ".", ".." and "./" with trailing slashes while collecting files to be dumped into the vfs overlay directory. Include the support for symlinks into components. Given the path: /install-dir/bin/../lib/clang/3.8.0/include/altivec.h, if "bin" component is a symlink, it's not safe to use `path::remove_dots` here, and `realpath` is used to get the right answer. Since `realpath` is expensive, we only do it at collecting time (which only happens during the crash reproducer) and cache the base directory for fast lookups. Overall, this makes the input to the VFS YAML file to be canonicalized to never contain traversal components. Differential Revision: http://reviews.llvm.org/D17104 rdar://problem/24499339 llvm-svn: 263617
Diffstat (limited to 'clang/lib/Basic/VirtualFileSystem.cpp')
-rw-r--r--clang/lib/Basic/VirtualFileSystem.cpp80
1 files changed, 64 insertions, 16 deletions
diff --git a/clang/lib/Basic/VirtualFileSystem.cpp b/clang/lib/Basic/VirtualFileSystem.cpp
index ba846c8..e1c4d71 100644
--- a/clang/lib/Basic/VirtualFileSystem.cpp
+++ b/clang/lib/Basic/VirtualFileSystem.cpp
@@ -112,6 +112,20 @@ bool FileSystem::exists(const Twine &Path) {
return Status && Status->exists();
}
+#ifndef NDEBUG
+static bool isTraversalComponent(StringRef Component) {
+ return Component.equals("..") || Component.equals(".");
+}
+
+static bool pathHasTraversal(StringRef Path) {
+ using namespace llvm::sys;
+ for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
+ if (isTraversalComponent(Comp))
+ return true;
+ return false;
+}
+#endif
+
//===-----------------------------------------------------------------------===/
// RealFileSystem implementation
//===-----------------------------------------------------------------------===/
@@ -819,6 +833,16 @@ class RedirectingFileSystem : public vfs::FileSystem {
bool UseExternalNames;
/// @}
+ /// Virtual file paths and external files could be canonicalized without "..",
+ /// "." and "./" in their paths. FIXME: some unittests currently fail on
+ /// win32 when using remove_dots and remove_leading_dotslash on paths.
+ bool UseCanonicalizedPaths =
+#ifdef LLVM_ON_WIN32
+ false;
+#else
+ true;
+#endif
+
friend class RedirectingFileSystemParser;
private:
@@ -954,7 +978,7 @@ class RedirectingFileSystemParser {
return true;
}
- std::unique_ptr<Entry> parseEntry(yaml::Node *N) {
+ std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS) {
yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
if (!M) {
error(N, "expected mapping node for file or directory entry");
@@ -994,7 +1018,17 @@ class RedirectingFileSystemParser {
if (Key == "name") {
if (!parseScalarString(I->getValue(), Value, Buffer))
return nullptr;
- Name = Value;
+
+ if (FS->UseCanonicalizedPaths) {
+ SmallString<256> Path(Value);
+ // Guarantee that old YAML files containing paths with ".." and "."
+ // are properly canonicalized before read into the VFS.
+ Path = sys::path::remove_leading_dotslash(Path);
+ sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ Name = Path.str();
+ } else {
+ Name = Value;
+ }
} else if (Key == "type") {
if (!parseScalarString(I->getValue(), Value, Buffer))
return nullptr;
@@ -1024,7 +1058,7 @@ class RedirectingFileSystemParser {
for (yaml::SequenceNode::iterator I = Contents->begin(),
E = Contents->end();
I != E; ++I) {
- if (std::unique_ptr<Entry> E = parseEntry(&*I))
+ if (std::unique_ptr<Entry> E = parseEntry(&*I, FS))
EntryArrayContents.push_back(std::move(E));
else
return nullptr;
@@ -1038,7 +1072,16 @@ class RedirectingFileSystemParser {
HasContents = true;
if (!parseScalarString(I->getValue(), Value, Buffer))
return nullptr;
- ExternalContentsPath = Value;
+ if (FS->UseCanonicalizedPaths) {
+ SmallString<256> Path(Value);
+ // Guarantee that old YAML files containing paths with ".." and "."
+ // are properly canonicalized before read into the VFS.
+ Path = sys::path::remove_leading_dotslash(Path);
+ sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ ExternalContentsPath = Path.str();
+ } else {
+ ExternalContentsPath = Value;
+ }
} else if (Key == "use-external-name") {
bool Val;
if (!parseScalarBool(I->getValue(), Val))
@@ -1149,7 +1192,7 @@ public:
for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
I != E; ++I) {
- if (std::unique_ptr<Entry> E = parseEntry(&*I))
+ if (std::unique_ptr<Entry> E = parseEntry(&*I, FS))
FS->Roots.push_back(std::move(E));
else
return false;
@@ -1228,6 +1271,14 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
if (std::error_code EC = makeAbsolute(Path))
return EC;
+ // Canonicalize path by removing ".", "..", "./", etc components. This is
+ // a VFS request, do bot bother about symlinks in the path components
+ // but canonicalize in order to perform the correct entry search.
+ if (UseCanonicalizedPaths) {
+ Path = sys::path::remove_leading_dotslash(Path);
+ sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ }
+
if (Path.empty())
return make_error_code(llvm::errc::invalid_argument);
@@ -1244,10 +1295,17 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
ErrorOr<Entry *>
RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
sys::path::const_iterator End, Entry *From) {
+#ifndef LLVM_ON_WIN32
+ assert(!isTraversalComponent(*Start) &&
+ !isTraversalComponent(From->getName()) &&
+ "Paths should not contain traversal components");
+#else
+ // FIXME: this is here to support windows, remove it once canonicalized
+ // paths become globally default.
if (Start->equals("."))
++Start;
+#endif
- // FIXME: handle ..
if (CaseSensitive ? !Start->equals(From->getName())
: !Start->equals_lower(From->getName()))
// failure to match
@@ -1366,16 +1424,6 @@ UniqueID vfs::getNextVirtualUniqueID() {
return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
}
-#ifndef NDEBUG
-static bool pathHasTraversal(StringRef Path) {
- using namespace llvm::sys;
- for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
- if (Comp == "." || Comp == "..")
- return true;
- return false;
-}
-#endif
-
void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
assert(sys::path::is_absolute(RealPath) && "real path not absolute");