From fecf0579406081010195d87cd5a74608c33d5004 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Tue, 7 Feb 2017 21:51:58 +0000 Subject: Fix bugs in filesystem detected by _LIBCPP_ASSERT. Recently I turned on libc++'s debug mode assertions when CMake is configured with -DLIBCXX_ENABLE_ASSERTIONS=ON. This change exposed assertion failures caused by bugs in filesystem. This patch fixes those failures. The first bug was that `PathParser` was using front()/back() on empty string views in order to get the address of the character. However this is UB on empty strings. Those operations now use data() to obtain the pointer. The second bug was that directory_iterator attempted to capture errno when it was unset and there was an assertion to detect this. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@294360 91177308-0d34-0410-b5e6-96231b3b80d8 --- src/experimental/filesystem/directory_iterator.cpp | 5 +++-- src/experimental/filesystem/path.cpp | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/experimental/filesystem/directory_iterator.cpp b/src/experimental/filesystem/directory_iterator.cpp index 8c9d05c2f..25135857d 100644 --- a/src/experimental/filesystem/directory_iterator.cpp +++ b/src/experimental/filesystem/directory_iterator.cpp @@ -45,11 +45,12 @@ inline bool set_or_throw(std::error_code& my_ec, inline path::string_type posix_readdir(DIR *dir_stream, error_code& ec) { struct dirent* dir_entry_ptr = nullptr; errno = 0; // zero errno in order to detect errors + ec.clear(); if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { - ec = capture_errno(); + if (errno) + ec = capture_errno(); return {}; } else { - ec.clear(); return dir_entry_ptr->d_name; } } diff --git a/src/experimental/filesystem/path.cpp b/src/experimental/filesystem/path.cpp index daf2c2bba..f49d4cd2d 100644 --- a/src/experimental/filesystem/path.cpp +++ b/src/experimental/filesystem/path.cpp @@ -56,13 +56,13 @@ public: } PosPtr peek() const noexcept { - auto End = &Path.back() + 1; auto TkEnd = getNextTokenStartPos(); + auto End = getAfterBack(); return TkEnd == End ? nullptr : TkEnd; } void increment() noexcept { - const PosPtr End = &Path.back() + 1; + const PosPtr End = getAfterBack(); const PosPtr Start = getNextTokenStartPos(); if (Start == End) return makeState(PS_AtEnd); @@ -109,7 +109,7 @@ public: } void decrement() noexcept { - const PosPtr REnd = &Path.front() - 1; + const PosPtr REnd = getBeforeFront(); const PosPtr RStart = getCurrentTokenStartPos() - 1; switch (State) { @@ -195,19 +195,27 @@ private: RawEntry = {}; } + PosPtr getAfterBack() const noexcept { + return Path.data() + Path.size(); + } + + PosPtr getBeforeFront() const noexcept { + return Path.data() - 1; + } + /// \brief Return a pointer to the first character after the currently /// lexed element. PosPtr getNextTokenStartPos() const noexcept { switch (State) { case PS_BeforeBegin: - return &Path.front(); + return Path.data(); case PS_InRootName: case PS_InRootDir: case PS_InFilenames: return &RawEntry.back() + 1; case PS_InTrailingSep: case PS_AtEnd: - return &Path.back() + 1; + return getAfterBack(); } _LIBCPP_UNREACHABLE(); } -- cgit v1.2.3