diff --git a/CMakeLists.txt b/CMakeLists.txt index c88caa07972..971928523dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,7 +149,6 @@ auto_sources(hfiles "*.h" "RECURSE" "${FOLLY_DIR}") REMOVE_MATCHES_FROM_LISTS(files hfiles MATCHES "^${FOLLY_DIR}/build/" - "^${FOLLY_DIR}/experimental/exception_tracer/" "^${FOLLY_DIR}/futures/exercises/" "^${FOLLY_DIR}/logging/example/" "^${FOLLY_DIR}/(.*/)?test/" diff --git a/folly/container/F14Map.h b/folly/container/F14Map.h index 430cbe7a113..f2ead4433a4 100644 --- a/folly/container/F14Map.h +++ b/folly/container/F14Map.h @@ -628,6 +628,11 @@ class F14BasicMap { return table_.prehash(key); } + template + void prefetchFirstMatchedValue(K const& key) const { + return table_.prefetchFirstMatchedValue(key); + } + FOLLY_ALWAYS_INLINE iterator find(key_type const& key) { return table_.makeIter(table_.find(key)); } diff --git a/folly/container/detail/F14Policy.h b/folly/container/detail/F14Policy.h index 4b44140f647..7c1211bda2d 100644 --- a/folly/container/detail/F14Policy.h +++ b/folly/container/detail/F14Policy.h @@ -469,11 +469,13 @@ class ValueContainerIterator : public ValueContainerIteratorBase { return cur; } - bool operator==(ValueContainerIterator const& rhs) const { - return underlying_ == rhs.underlying_; + friend bool operator==(ValueContainerIterator const& lhs, + ValueContainerIterator const& rhs) { + return lhs.underlying_ == rhs.underlying_; } - bool operator!=(ValueContainerIterator const& rhs) const { - return !(*this == rhs); + friend bool operator!=(ValueContainerIterator const& lhs, + ValueContainerIterator const& rhs) { + return !(lhs == rhs); } private: @@ -698,11 +700,13 @@ class NodeContainerIterator : public BaseIter> { return cur; } - bool operator==(NodeContainerIterator const& rhs) const { - return underlying_ == rhs.underlying_; + friend bool operator==(NodeContainerIterator const& lhs, + NodeContainerIterator const& rhs) { + return lhs.underlying_ == rhs.underlying_; } - bool operator!=(NodeContainerIterator const& rhs) const { - return !(*this == rhs); + friend bool operator!=(NodeContainerIterator const& lhs, + NodeContainerIterator const& rhs) { + return !(lhs == rhs); } private: @@ -936,11 +940,13 @@ class VectorContainerIterator : public BaseIter { return cur; } - bool operator==(VectorContainerIterator const& rhs) const { - return current_ == rhs.current_; + friend bool operator==(VectorContainerIterator const& lhs, + VectorContainerIterator const& rhs) { + return lhs.current_ == rhs.current_; } - bool operator!=(VectorContainerIterator const& rhs) const { - return !(*this == rhs); + friend bool operator!=(VectorContainerIterator const& lhs, + VectorContainerIterator const& rhs) { + return !(lhs == rhs); } private: diff --git a/folly/container/detail/F14Table.h b/folly/container/detail/F14Table.h index 9aa2b8af723..591a40e63bf 100644 --- a/folly/container/detail/F14Table.h +++ b/folly/container/detail/F14Table.h @@ -1323,6 +1323,19 @@ class F14Table : public Policy { prefetchAddr(firstChunk); return F14HashToken(std::move(hp)); } + + // Prefetch the first matched value if there is at least one match in tags + template + void prefetchFirstMatchedValue(K const& key) const { + auto hp = splitHash(this->computeKeyHash(key)); + std::size_t index = hp.first; + ChunkPtr chunk = chunks_ + (index & chunkMask_); + auto hits = chunk->tagMatchIter(hp.second); + if (hits.hasNext()) { + auto i = hits.next(); + this->prefetchValue(chunk->item(i)); + } + } template FOLLY_ALWAYS_INLINE ItemIter find(K const& key) const { diff --git a/folly/dynamic-inl.h b/folly/dynamic-inl.h index 1262e117d2d..21e1567aeff 100644 --- a/folly/dynamic-inl.h +++ b/folly/dynamic-inl.h @@ -239,6 +239,9 @@ struct dynamic::item_iterator : detail::IteratorAdaptor< /* implicit */ item_iterator(dynamic::ObjectImpl::iterator b) : Super(b) {} using object_type = dynamic::ObjectImpl; + + using Super::operator==; + using Super::operator!=; }; struct dynamic::value_iterator : detail::IteratorAdaptor< @@ -256,6 +259,9 @@ struct dynamic::value_iterator : detail::IteratorAdaptor< using object_type = dynamic::ObjectImpl; dynamic& dereference() const { return base()->second; } + + using Super::operator==; + using Super::operator!=; }; struct dynamic::const_item_iterator @@ -276,6 +282,9 @@ struct dynamic::const_item_iterator /* implicit */ const_item_iterator(item_iterator i) : Super(i.base()) {} using object_type = dynamic::ObjectImpl const; + + using Super::operator==; + using Super::operator!=; }; struct dynamic::const_key_iterator : detail::IteratorAdaptor< @@ -294,6 +303,9 @@ struct dynamic::const_key_iterator : detail::IteratorAdaptor< using object_type = dynamic::ObjectImpl const; dynamic const& dereference() const { return base()->first; } + + using Super::operator==; + using Super::operator!=; }; struct dynamic::const_value_iterator : detail::IteratorAdaptor< @@ -315,6 +327,9 @@ struct dynamic::const_value_iterator : detail::IteratorAdaptor< using object_type = dynamic::ObjectImpl const; dynamic const& dereference() const { return base()->second; } + + using Super::operator==; + using Super::operator!=; }; ////////////////////////////////////////////////////////////////////// diff --git a/folly/experimental/symbolizer/Dwarf.cpp b/folly/experimental/symbolizer/Dwarf.cpp index f15574bd7ec..b55aa5145e4 100644 --- a/folly/experimental/symbolizer/Dwarf.cpp +++ b/folly/experimental/symbolizer/Dwarf.cpp @@ -458,6 +458,9 @@ bool Dwarf::findDebugInfoOffset( * Best effort: * - fills @inlineFrames if mode == FULL_WITH_INLINE, * - calls @eachParameterName on the function parameters. + * + * if @checkAddress is true, we verify that the address is mapped to + * a range in this CU before running the line number VM */ bool Dwarf::findLocation( uintptr_t address, @@ -465,7 +468,8 @@ bool Dwarf::findLocation( detail::CompilationUnit& cu, LocationInfo& locationInfo, folly::Range inlineFrames, - folly::FunctionRef eachParameterName) const { + folly::FunctionRef eachParameterName, + bool checkAddress) const { detail::Die die = getDieAtOffset(cu, cu.firstDie); // Partial compilation unit (DW_TAG_partial_unit) is not supported. FOLLY_SAFE_CHECK( @@ -477,41 +481,98 @@ bool Dwarf::findLocation( folly::StringPiece compilationDirectory; folly::Optional mainFileName; folly::Optional baseAddrCU; + folly::Optional rangesOffset; + bool seenLowPC = false; + bool seenHighPC = false; + enum : unsigned { + kStmtList = 1U << 0, + kCompDir = 1U << 1, + kName = 1U << 2, + kLowPC = 1U << 3, + kHighPCOrRanges = 1U << 4, + }; + unsigned expectedAttributes = kStmtList | kCompDir | kName | kLowPC; + bool foundAddress = !checkAddress; + if (!foundAddress) { + expectedAttributes |= kHighPCOrRanges; + } forEachAttribute(cu, die, [&](const detail::Attribute& attr) { switch (attr.spec.name) { case DW_AT_stmt_list: + expectedAttributes &= ~kStmtList; // Offset in .debug_line for the line number VM program for this // compilation unit lineOffset = boost::get(attr.attrValue); break; case DW_AT_comp_dir: + expectedAttributes &= ~kCompDir; // Compilation directory compilationDirectory = boost::get(attr.attrValue); break; case DW_AT_name: + expectedAttributes &= ~kName; // File name of main file being compiled mainFileName = boost::get(attr.attrValue); break; case DW_AT_low_pc: - case DW_AT_entry_pc: - // 2.17.1: historically DW_AT_low_pc was used. DW_AT_entry_pc was - // introduced in DWARF3. Support either to determine the base address of - // the CU. + expectedAttributes &= ~kLowPC; baseAddrCU = boost::get(attr.attrValue); + if (!foundAddress) { + if (address < *baseAddrCU) { + return false; + } + seenLowPC = true; + if (seenHighPC) { + foundAddress = true; + } else if (rangesOffset) { + if (!isAddrInRangeList(address, baseAddrCU, *rangesOffset, + cu.addrSize)) { + return false; + } + foundAddress = true; + } + } + break; + case DW_AT_high_pc: + expectedAttributes &= ~kHighPCOrRanges; + if (!foundAddress) { + if (address >= boost::get(attr.attrValue)) { + return false; + } + seenHighPC = true; + foundAddress = seenLowPC; + } + break; + case DW_AT_ranges: + // 3.1.1: CU entries have: + // - either DW_AT_low_pc and DW_AT_high_pc + // OR + // - DW_AT_ranges and optional DW_AT_low_pc + expectedAttributes &= ~kHighPCOrRanges; + if (!foundAddress) { + rangesOffset = boost::get(attr.attrValue); + if (seenLowPC) { + if (!isAddrInRangeList(address, baseAddrCU, *rangesOffset, + cu.addrSize)) { + return false; + } + foundAddress = true; + } + } break; } - return true; // continue forEachAttribute + return (expectedAttributes != 0); // continue forEachAttribute }); + if (!foundAddress || !lineOffset) { + return false; + } + if (mainFileName) { locationInfo.hasMainFile = true; locationInfo.mainFile = Path(compilationDirectory, "", *mainFileName); } - if (!lineOffset) { - return false; - } - folly::StringPiece lineSection(debugLine_); lineSection.advance(*lineOffset); LineNumberVM lineVM(lineSection, compilationDirectory); @@ -660,7 +721,8 @@ bool Dwarf::findAddress( // Read compilation unit header from .debug_info auto unit = getCompilationUnit(debugInfo_, offset); return findLocation( - address, mode, unit, locationInfo, inlineFrames, eachParameterName); + address, mode, unit, locationInfo, inlineFrames, eachParameterName, + false /*checkAddress*/); } else if (mode == LocationInfoMode::FAST) { // NOTE: Clang (when using -gdwarf-aranges) doesn't generate entries // in .debug_aranges for some functions, but always generates @@ -688,7 +750,8 @@ bool Dwarf::findAddress( unit, locationInfo, inlineFrames, - eachParameterName)) { + eachParameterName, + true /*checkAddress*/)) { return true; } } diff --git a/folly/experimental/symbolizer/Dwarf.h b/folly/experimental/symbolizer/Dwarf.h index 564e419df1d..479b1f1e660 100644 --- a/folly/experimental/symbolizer/Dwarf.h +++ b/folly/experimental/symbolizer/Dwarf.h @@ -122,6 +122,9 @@ class Dwarf { * Best effort: * - fills @inlineFrames if mode == FULL_WITH_INLINE, * - calls @eachParameterName on the function parameters. + * + * if @checkAddress is true, we verify that the address is mapped to + * a range in this CU before running the line number VM */ bool findLocation( uintptr_t address, @@ -129,7 +132,8 @@ class Dwarf { detail::CompilationUnit& cu, LocationInfo& info, folly::Range inlineFrames, - folly::FunctionRef eachParameterName) const; + folly::FunctionRef eachParameterName, + bool checkAddress = true) const; /** * Finds a subprogram debugging info entry that contains a given address among diff --git a/folly/experimental/symbolizer/SignalHandler.cpp b/folly/experimental/symbolizer/SignalHandler.cpp index 2df79a24ebb..5dd0d94ea72 100644 --- a/folly/experimental/symbolizer/SignalHandler.cpp +++ b/folly/experimental/symbolizer/SignalHandler.cpp @@ -478,10 +478,11 @@ void signalHandler(int signum, siginfo_t* info, void* uctx) { #endif // FOLLY_USE_SYMBOLIZER -// Small sigaltstack size threshold. -// 8931 is known to cause the signal handler to stack overflow during -// symbolization even for a simple one-liner "kill(getpid(), SIGTERM)". -constexpr size_t kSmallSigAltStackSize = 8931; +// Small sigaltstack size threshold. If the alternate stack is too small we +// must use UnsafeSelfAllocateStackTracePrinter() to avoid stack overflow +// during symbolization of a signal. 48K has been observed to have stack +// overflow, and 56K has been observed to work. +constexpr size_t kSmallSigAltStackSize = 65536; FOLLY_MAYBE_UNUSED bool isSmallSigAltStackEnabled() { stack_t ss; diff --git a/folly/fibers/Fiber.cpp b/folly/fibers/Fiber.cpp index 495dd5f85bb..81a0ca32db6 100644 --- a/folly/fibers/Fiber.cpp +++ b/folly/fibers/Fiber.cpp @@ -79,7 +79,7 @@ Fiber::Fiber(FiberManager& fiberManager) void Fiber::init(bool recordStackUsed) { // It is necessary to disable the logic for ASAN because we change // the fiber's stack. -#ifndef FOLLY_SANITIZE_ADDRESS +#ifndef FOLLY_LIBRARY_SANITIZE_ADDRESS recordStackUsed_ = recordStackUsed; if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) { CHECK_EQ( @@ -103,7 +103,7 @@ void Fiber::init(bool recordStackUsed) { } Fiber::~Fiber() { -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS if (asanFakeStack_ != nullptr) { fiberManager_.freeFakeStack(asanFakeStack_); } @@ -115,7 +115,7 @@ Fiber::~Fiber() { void Fiber::recordStackPosition() { // For ASAN builds, functions may run on fake stack. // So we cannot get meaningful stack position. -#ifndef FOLLY_SANITIZE_ADDRESS +#ifndef FOLLY_LIBRARY_SANITIZE_ADDRESS int stackDummy; auto currentPosition = static_cast( fiberStackLimit_ + fiberStackSize_ - @@ -126,7 +126,7 @@ void Fiber::recordStackPosition() { } [[noreturn]] void Fiber::fiberFunc() { -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS fiberManager_.registerFinishSwitchStackWithAsan( nullptr, &asanMainStackBase_, &asanMainStackSize_); #endif diff --git a/folly/fibers/Fiber.h b/folly/fibers/Fiber.h index c83127a8efd..9344096aefb 100644 --- a/folly/fibers/Fiber.h +++ b/folly/fibers/Fiber.h @@ -193,7 +193,7 @@ class Fiber { folly::IntrusiveListHook globalListHook_; /**< list hook for global list */ std::thread::id threadId_{}; -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS void* asanFakeStack_{nullptr}; const void* asanMainStackBase_{nullptr}; size_t asanMainStackSize_{0}; diff --git a/folly/fibers/FiberManager.cpp b/folly/fibers/FiberManager.cpp index f64f3aa52e4..40c7f8c70a7 100644 --- a/folly/fibers/FiberManager.cpp +++ b/folly/fibers/FiberManager.cpp @@ -33,7 +33,7 @@ #include #include -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS #ifndef _WIN32 #include @@ -217,7 +217,7 @@ void FiberManager::FibersPoolResizer::run() { } } -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS void FiberManager::registerStartSwitchStackWithAsan( void** saveFakeStack, @@ -336,7 +336,7 @@ static AsanUnpoisonMemoryRegionFuncPtr getUnpoisonMemoryRegionFunc() { return nullptr; } -#endif // FOLLY_SANITIZE_ADDRESS +#endif // FOLLY_LIBRARY_SANITIZE_ADDRESS // TVOS and WatchOS platforms have SIGSTKSZ but not sigaltstack #if defined(SIGSTKSZ) && !FOLLY_APPLE_TVOS && !FOLLY_APPLE_WATCHOS diff --git a/folly/fibers/FiberManagerInternal-inl.h b/folly/fibers/FiberManagerInternal-inl.h index 2da28158277..ad53ef7948f 100644 --- a/folly/fibers/FiberManagerInternal-inl.h +++ b/folly/fibers/FiberManagerInternal-inl.h @@ -66,7 +66,7 @@ inline void FiberManager::ensureLoopScheduled() { inline void FiberManager::activateFiber(Fiber* fiber) { DCHECK_EQ(activeFiber_, (Fiber*)nullptr); -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS DCHECK(!fiber->asanMainStackBase_); DCHECK(!fiber->asanMainStackSize_); auto stack = fiber->getStack(); @@ -86,7 +86,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) { inline void FiberManager::deactivateFiber(Fiber* fiber) { DCHECK_EQ(activeFiber_, fiber); -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS DCHECK(fiber->asanMainStackBase_); DCHECK(fiber->asanMainStackSize_); diff --git a/folly/fibers/FiberManagerInternal.h b/folly/fibers/FiberManagerInternal.h index 4f47f475853..c3cd52e9288 100644 --- a/folly/fibers/FiberManagerInternal.h +++ b/folly/fibers/FiberManagerInternal.h @@ -601,7 +601,7 @@ class FiberManager : public ::folly::Executor { void runReadyFiber(Fiber* fiber); void remoteReadyInsert(Fiber* fiber); -#ifdef FOLLY_SANITIZE_ADDRESS +#ifdef FOLLY_LIBRARY_SANITIZE_ADDRESS // These methods notify ASAN when a fiber is entered/exited so that ASAN can // find the right stack extents when it needs to poison/unpoison the stack. @@ -617,7 +617,7 @@ class FiberManager : public ::folly::Executor { void freeFakeStack(void* fakeStack); void unpoisonFiberStack(const Fiber* fiber); -#endif // FOLLY_SANITIZE_ADDRESS +#endif // FOLLY_LIBRARY_SANITIZE_ADDRESS bool alternateSignalStackRegistered_{false}; diff --git a/folly/io/IOBuf.h b/folly/io/IOBuf.h index d971d9e6352..faff72ac5e3 100644 --- a/folly/io/IOBuf.h +++ b/folly/io/IOBuf.h @@ -1692,6 +1692,11 @@ class IOBuf::Iterator : public detail::IteratorFacade< IOBuf::Iterator, ByteRange const, std::forward_iterator_tag> { + using Super = detail::IteratorFacade< + IOBuf::Iterator, + ByteRange const, + std::forward_iterator_tag>; + public: // Note that IOBufs are stored as a circular list without a guard node, // so pos == end is ambiguous (it may mean "begin" or "end"). To solve @@ -1718,6 +1723,9 @@ class IOBuf::Iterator : public detail::IteratorFacade< return *this; } + using Super::operator==; + using Super::operator!=; + const ByteRange& dereference() const { return val_; } bool equal(const Iterator& other) const {