Commit 3468cb59 authored by Andrew Gallagher's avatar Andrew Gallagher Committed by Dave Watson

Various Dwarf::Path fixes

Summary:
- Allow both `baseDir` and `subDir` to be empty.  This can happen
if DW_AT_comp_dir is `.` and gets simplified to the empty string.
(The DWARF standard doesn't appear to disallow relative dirs here,
but I couldn't find anthing definitive).
- Fix `./` prefix  stripping to avoid making paths like `.///hello` absolute.
- Fix `/` suffix stripping to avoid making the root dir reference (`/`) empty.
- Do `baseDir` and `subDir` swapping after simplification.

Test Plan: Added unittests.

Reviewed By: njormrod@fb.com

Subscribers: trunkagent, sdwilsh, folly-diffs@

FB internal diff: D1747978

Signature: t1:1747978:1419014942:87f14cb31b8c19b524d7a95b14d63cf5661a8634
parent 5a65b2bd
...@@ -131,6 +131,10 @@ void simplifyPath(folly::StringPiece& sp) { ...@@ -131,6 +131,10 @@ void simplifyPath(folly::StringPiece& sp) {
} }
if (sp.removePrefix("./")) { if (sp.removePrefix("./")) {
// Also remove any subsequent slashes to avoid making this path absolute.
while (sp.startsWith('/')) {
sp.advance(1);
}
continue; continue;
} }
...@@ -143,8 +147,8 @@ void simplifyPath(folly::StringPiece& sp) { ...@@ -143,8 +147,8 @@ void simplifyPath(folly::StringPiece& sp) {
return; return;
} }
// Strip trailing slashes // Strip trailing slashes, except when this is the root path.
while (sp.removeSuffix('/')) { } while (sp.size() > 1 && sp.removeSuffix('/')) { }
if (sp.removeSuffix("/.")) { if (sp.removeSuffix("/.")) {
continue; continue;
...@@ -180,29 +184,42 @@ Dwarf::Path::Path(folly::StringPiece baseDir, folly::StringPiece subDir, ...@@ -180,29 +184,42 @@ Dwarf::Path::Path(folly::StringPiece baseDir, folly::StringPiece subDir,
baseDir_.clear(); // subDir_ is absolute baseDir_.clear(); // subDir_ is absolute
} }
// Make sure that baseDir_ isn't empty; subDir_ may be
if (baseDir_.empty()) {
swap(baseDir_, subDir_);
}
simplifyPath(baseDir_); simplifyPath(baseDir_);
simplifyPath(subDir_); simplifyPath(subDir_);
simplifyPath(file_); simplifyPath(file_);
// Make sure it's never the case that baseDir_ is empty, but subDir_ isn't.
if (baseDir_.empty()) {
swap(baseDir_, subDir_);
}
} }
size_t Dwarf::Path::size() const { size_t Dwarf::Path::size() const {
if (baseDir_.empty()) { size_t size = 0;
assert(subDir_.empty()); bool needsSlash = false;
return file_.size();
if (!baseDir_.empty()) {
size += baseDir_.size();
needsSlash = !baseDir_.endsWith('/');
}
if (!subDir_.empty()) {
size += needsSlash;
size += subDir_.size();
needsSlash = !subDir_.endsWith('/');
} }
return if (!file_.empty()) {
baseDir_.size() + !subDir_.empty() + subDir_.size() + !file_.empty() + size += needsSlash;
file_.size(); size += file_.size();
}
return size;
} }
size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const { size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const {
size_t totalSize = 0; size_t totalSize = 0;
bool needsSlash = false;
auto append = [&] (folly::StringPiece sp) { auto append = [&] (folly::StringPiece sp) {
if (bufSize >= 2) { if (bufSize >= 2) {
...@@ -216,14 +233,17 @@ size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const { ...@@ -216,14 +233,17 @@ size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const {
if (!baseDir_.empty()) { if (!baseDir_.empty()) {
append(baseDir_); append(baseDir_);
needsSlash = !baseDir_.endsWith('/');
} }
if (!subDir_.empty()) { if (!subDir_.empty()) {
assert(!baseDir_.empty()); if (needsSlash) {
append("/"); append("/");
}
append(subDir_); append(subDir_);
needsSlash = !subDir_.endsWith('/');
} }
if (!file_.empty()) { if (!file_.empty()) {
if (!baseDir_.empty()) { if (needsSlash) {
append("/"); append("/");
} }
append(file_); append(file_);
...@@ -237,17 +257,23 @@ size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const { ...@@ -237,17 +257,23 @@ size_t Dwarf::Path::toBuffer(char* buf, size_t bufSize) const {
void Dwarf::Path::toString(std::string& dest) const { void Dwarf::Path::toString(std::string& dest) const {
size_t initialSize = dest.size(); size_t initialSize = dest.size();
bool needsSlash = false;
dest.reserve(initialSize + size()); dest.reserve(initialSize + size());
if (!baseDir_.empty()) { if (!baseDir_.empty()) {
dest.append(baseDir_.begin(), baseDir_.end()); dest.append(baseDir_.begin(), baseDir_.end());
needsSlash = baseDir_.endsWith('/');
} }
if (!subDir_.empty()) { if (!subDir_.empty()) {
assert(!baseDir_.empty()); if (needsSlash) {
dest.push_back('/'); dest.push_back('/');
}
dest.append(subDir_.begin(), subDir_.end()); dest.append(subDir_.begin(), subDir_.end());
needsSlash = subDir_.endsWith('/');
} }
if (!file_.empty()) { if (!file_.empty()) {
dest.push_back('/'); if (needsSlash) {
dest.push_back('/');
}
dest.append(file_.begin(), file_.end()); dest.append(file_.begin(), file_.end());
} }
assert(dest.size() == initialSize + size()); assert(dest.size() == initialSize + size());
......
/*
* Copyright 2014 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/symbolizer/Dwarf.h>
#include <gtest/gtest.h>
using folly::symbolizer::Dwarf;
void checkPath(
std::string expectedPath,
std::string expectedBaseDir,
std::string expectedSubDir,
std::string expectedFile,
std::string rawBaseDir,
std::string rawSubDir,
std::string rawFile) {
Dwarf::Path path(rawBaseDir, rawSubDir, rawFile);
CHECK_EQ(expectedBaseDir, path.baseDir())
<< "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedSubDir, path.subDir())
<< "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedFile, path.file())
<< "Path(" << rawBaseDir << ", " << rawSubDir << ", " << rawFile << ")";
CHECK_EQ(expectedPath, path.toString());
// Check the the `toBuffer` function.
char buf[1024];
size_t len;
len = path.toBuffer(buf, 1024);
CHECK_EQ(expectedPath, std::string(buf, len));
}
TEST(Dwarf, Path) {
checkPath(
"hello.cpp",
"",
"",
"hello.cpp",
"",
"",
"hello.cpp");
checkPath(
"foo/hello.cpp",
"foo",
"",
"hello.cpp",
"foo",
"",
"hello.cpp");
checkPath(
"foo/hello.cpp",
"foo",
"",
"hello.cpp",
"",
"foo",
"hello.cpp");
checkPath(
"hello.cpp",
"",
"",
"hello.cpp",
"./////",
"./////",
"hello.cpp");
checkPath(
"/hello.cpp",
"/",
"",
"hello.cpp",
"/////",
"./////",
"hello.cpp");
checkPath(
"/hello.cpp",
"/",
"",
"hello.cpp",
"/./././././././",
"",
"hello.cpp");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment