From e4b4ab6d26f885f4b12624e5d375521070d8ba3d Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Wed, 8 May 2019 02:11:07 +0000 Subject: [PATCH] [Support] Add error handling to sys::Process::getPageSize(). This patch changes the return type of sys::Process::getPageSize to Expected to account for the fact that the underlying syscalls used to obtain the page size may fail (see below). For clients who use the page size as an optimization only this patch adds a new method, getPageSizeEstimate, which calls through to getPageSize but discards any error returned and substitues a "reasonable" page size estimate estimate instead. All existing LLVM clients are updated to call getPageSizeEstimate rather than getPageSize. On Unix, sys::Process::getPageSize is implemented in terms of getpagesize or sysconf, depending on which macros are set. The sysconf call is documented to return -1 on failure. On Darwin getpagesize is implemented in terms of sysconf and may also fail (though the manpage documentation does not mention this). These failures have been observed in practice when highly restrictive sandbox permissions have been applied. Without this patch, the result is that getPageSize returns -1, which wreaks havoc on any subsequent code that was assuming a sane page size value. Reviewers: dblaikie, echristo Subscribers: kristina, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59107 llvm-svn: 360221 --- .../ExecutionEngine/Orc/IndirectionUtils.h | 4 ++-- .../Orc/OrcRemoteTargetServer.h | 6 +++--- llvm/include/llvm/Support/Process.h | 21 ++++++++++++++++++- llvm/lib/ExecutionEngine/JITLink/JITLink.cpp | 4 ++-- .../lib/ExecutionEngine/Orc/OrcABISupport.cpp | 10 ++++----- .../ExecutionEngine/SectionMemoryManager.cpp | 4 ++-- llvm/lib/Support/MemoryBuffer.cpp | 2 +- llvm/lib/Support/Unix/Memory.inc | 4 ++-- llvm/lib/Support/Unix/Path.inc | 2 +- llvm/lib/Support/Unix/Process.inc | 5 ++++- llvm/lib/Support/Windows/Process.inc | 2 +- llvm/unittests/Support/MemoryTest.cpp | 2 +- 12 files changed, 44 insertions(+), 22 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index 2ea9ac1c2b2f..a7ed5372d1e4 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -146,13 +146,13 @@ private: std::error_code EC; auto TrampolineBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( - sys::Process::getPageSize(), nullptr, + sys::Process::getPageSizeEstimate(), nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) return errorCodeToError(EC); unsigned NumTrampolines = - (sys::Process::getPageSize() - ORCABI::PointerSize) / + (sys::Process::getPageSizeEstimate() - ORCABI::PointerSize) / ORCABI::TrampolineSize; uint8_t *TrampolineMem = static_cast(TrampolineBlock.base()); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index 968448112be9..4c8e2ea1a7be 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -299,13 +299,13 @@ private: std::error_code EC; auto TrampolineBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( - sys::Process::getPageSize(), nullptr, + sys::Process::getPageSizeEstimate(), nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC)); if (EC) return errorCodeToError(EC); uint32_t NumTrampolines = - (sys::Process::getPageSize() - TargetT::PointerSize) / + (sys::Process::getPageSizeEstimate() - TargetT::PointerSize) / TargetT::TrampolineSize; uint8_t *TrampolineMem = static_cast(TrampolineBlock.base()); @@ -335,7 +335,7 @@ private: handleGetRemoteInfo() { std::string ProcessTriple = sys::getProcessTriple(); uint32_t PointerSize = TargetT::PointerSize; - uint32_t PageSize = sys::Process::getPageSize(); + uint32_t PageSize = sys::Process::getPageSizeEstimate(); uint32_t TrampolineSize = TargetT::TrampolineSize; uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize; LLVM_DEBUG(dbgs() << " Remote info:\n" diff --git a/llvm/include/llvm/Support/Process.h b/llvm/include/llvm/Support/Process.h index 9a70304f5c70..67e37912519b 100644 --- a/llvm/include/llvm/Support/Process.h +++ b/llvm/include/llvm/Support/Process.h @@ -28,6 +28,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Chrono.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/Error.h" #include namespace llvm { @@ -41,7 +42,25 @@ namespace sys { /// current executing process. class Process { public: - static unsigned getPageSize(); + /// Get the process's page size. + /// This may fail if the underlying syscall returns an error. In most cases, + /// page size information is used for optimization, and this error can be + /// safely discarded by calling consumeError, and an estimated page size + /// substituted instead. + static Expected getPageSize(); + + /// Get the process's estimated page size. + /// This function always succeeds, but if the underlying syscall to determine + /// the page size fails then this will silently return an estimated page size. + /// The estimated page size is guaranteed to be a power of 2. + static unsigned getPageSizeEstimate() { + if (auto PageSize = getPageSize()) + return *PageSize; + else { + consumeError(PageSize.takeError()); + return 4096; + } + } /// Return process memory usage. /// This static function will return the total amount of memory allocated diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 3169011f0825..1cea043f7613 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -194,12 +194,12 @@ InProcessMemoryManager::allocate(const SegmentsRequestMap &Request) { for (auto &KV : Request) { auto &Seg = KV.second; - if (Seg.getContentAlignment() > sys::Process::getPageSize()) + if (Seg.getContentAlignment() > sys::Process::getPageSizeEstimate()) return make_error("Cannot request higher than page " "alignment", inconvertibleErrorCode()); - if (sys::Process::getPageSize() % Seg.getContentAlignment() != 0) + if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0) return make_error("Page size is not a multiple of " "alignment", inconvertibleErrorCode()); diff --git a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp index 4bf52864107b..8ed23de419d1 100644 --- a/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp +++ b/llvm/lib/ExecutionEngine/Orc/OrcABISupport.cpp @@ -147,7 +147,7 @@ Error OrcAArch64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, const unsigned StubSize = IndirectStubsInfo::StubSize; // Emit at least MinStubs, rounded up to fill the pages allocated. - unsigned PageSize = sys::Process::getPageSize(); + static const unsigned PageSize = sys::Process::getPageSizeEstimate(); unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize; unsigned NumStubs = (NumPages * PageSize) / StubSize; @@ -229,7 +229,7 @@ Error OrcX86_64_Base::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, const unsigned StubSize = IndirectStubsInfo::StubSize; // Emit at least MinStubs, rounded up to fill the pages allocated. - unsigned PageSize = sys::Process::getPageSize(); + static const unsigned PageSize = sys::Process::getPageSizeEstimate(); unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize; unsigned NumStubs = (NumPages * PageSize) / StubSize; @@ -497,7 +497,7 @@ Error OrcI386::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, const unsigned StubSize = IndirectStubsInfo::StubSize; // Emit at least MinStubs, rounded up to fill the pages allocated. - unsigned PageSize = sys::Process::getPageSize(); + static const unsigned PageSize = sys::Process::getPageSizeEstimate(); unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize; unsigned NumStubs = (NumPages * PageSize) / StubSize; @@ -683,7 +683,7 @@ Error OrcMips32_Base::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, const unsigned StubSize = IndirectStubsInfo::StubSize; // Emit at least MinStubs, rounded up to fill the pages allocated. - unsigned PageSize = sys::Process::getPageSize(); + static const unsigned PageSize = sys::Process::getPageSizeEstimate(); unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize; unsigned NumStubs = (NumPages * PageSize) / StubSize; @@ -929,7 +929,7 @@ Error OrcMips64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo, const unsigned StubSize = IndirectStubsInfo::StubSize; // Emit at least MinStubs, rounded up to fill the pages allocated. - unsigned PageSize = sys::Process::getPageSize(); + static const unsigned PageSize = sys::Process::getPageSizeEstimate(); unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize; unsigned NumStubs = (NumPages * PageSize) / StubSize; diff --git a/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp b/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp index ba277796dd53..2c0cfeb8a9ac 100644 --- a/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp +++ b/llvm/lib/ExecutionEngine/SectionMemoryManager.cpp @@ -172,7 +172,7 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) { } static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) { - static const size_t PageSize = sys::Process::getPageSize(); + static const size_t PageSize = sys::Process::getPageSizeEstimate(); size_t StartOverlap = (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize; @@ -244,7 +244,7 @@ public: unsigned Flags, std::error_code &EC) override { // allocateMappedMemory calls mmap(2). We round up a request size // to page size to get extra space for free. - static const size_t PageSize = sys::Process::getPageSize(); + static const size_t PageSize = sys::Process::getPageSizeEstimate(); size_t ReqBytes = (NumBytes + PageSize - 1) & ~(PageSize - 1); return sys::Memory::allocateMappedMemory(ReqBytes, NearBlock, Flags, EC); } diff --git a/llvm/lib/Support/MemoryBuffer.cpp b/llvm/lib/Support/MemoryBuffer.cpp index 3f13d4d3552a..92e39e118b90 100644 --- a/llvm/lib/Support/MemoryBuffer.cpp +++ b/llvm/lib/Support/MemoryBuffer.cpp @@ -417,7 +417,7 @@ static ErrorOr> getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, bool IsVolatile) { - static int PageSize = sys::Process::getPageSize(); + static int PageSize = sys::Process::getPageSizeEstimate(); // Default is to map the full file. if (MapSize == uint64_t(-1)) { diff --git a/llvm/lib/Support/Unix/Memory.inc b/llvm/lib/Support/Unix/Memory.inc index b8f5df5f72e9..affdb7e70d95 100644 --- a/llvm/lib/Support/Unix/Memory.inc +++ b/llvm/lib/Support/Unix/Memory.inc @@ -103,7 +103,7 @@ Memory::allocateMappedMemory(size_t NumBytes, // Use any near hint and the page size to set a page-aligned starting address uintptr_t Start = NearBlock ? reinterpret_cast(NearBlock->base()) + NearBlock->size() : 0; - static const size_t PageSize = Process::getPageSize(); + static const size_t PageSize = Process::getPageSizeEstimate(); if (Start && Start % PageSize) Start += PageSize - Start % PageSize; @@ -149,7 +149,7 @@ Memory::releaseMappedMemory(MemoryBlock &M) { std::error_code Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { - static const size_t PageSize = Process::getPageSize(); + static const size_t PageSize = Process::getPageSizeEstimate(); if (M.Address == nullptr || M.Size == 0) return std::error_code(); diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index fb14422ba33a..c2f78e79b876 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -786,7 +786,7 @@ const char *mapped_file_region::const_data() const { } int mapped_file_region::alignment() { - return Process::getPageSize(); + return Process::getPageSizeEstimate(); } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc index 7c834f971146..78c123493e1d 100644 --- a/llvm/lib/Support/Unix/Process.inc +++ b/llvm/lib/Support/Unix/Process.inc @@ -69,7 +69,7 @@ static std::pair getRUsage // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and // offset in mmap(3) should be aligned to the AllocationGranularity. -unsigned Process::getPageSize() { +Expected Process::getPageSize() { #if defined(HAVE_GETPAGESIZE) static const int page_size = ::getpagesize(); #elif defined(HAVE_SYSCONF) @@ -77,6 +77,9 @@ unsigned Process::getPageSize() { #else #error Cannot get the page size on this machine #endif + if (page_size == -1) + return errorCodeToError(std::error_code(errno, std::generic_category())); + return static_cast(page_size); } diff --git a/llvm/lib/Support/Windows/Process.inc b/llvm/lib/Support/Windows/Process.inc index b3c9aa0b83cb..4b91f9f7fc66 100644 --- a/llvm/lib/Support/Windows/Process.inc +++ b/llvm/lib/Support/Windows/Process.inc @@ -56,7 +56,7 @@ static unsigned computePageSize() { return static_cast(info.dwPageSize); } -unsigned Process::getPageSize() { +Expected Process::getPageSize() { static unsigned Ret = computePageSize(); return Ret; } diff --git a/llvm/unittests/Support/MemoryTest.cpp b/llvm/unittests/Support/MemoryTest.cpp index 33cc3edb815c..dc5f606688f9 100644 --- a/llvm/unittests/Support/MemoryTest.cpp +++ b/llvm/unittests/Support/MemoryTest.cpp @@ -50,7 +50,7 @@ class MappedMemoryTest : public ::testing::TestWithParam { public: MappedMemoryTest() { Flags = GetParam(); - PageSize = sys::Process::getPageSize(); + PageSize = sys::Process::getPageSizeEstimate(); } protected: