]> granicus.if.org Git - llvm/commitdiff
[Support] Add error handling to sys::Process::getPageSize().
authorLang Hames <lhames@gmail.com>
Wed, 8 May 2019 02:11:07 +0000 (02:11 +0000)
committerLang Hames <lhames@gmail.com>
Wed, 8 May 2019 02:11:07 +0000 (02:11 +0000)
This patch changes the return type of sys::Process::getPageSize to
Expected<unsigned> 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.

<rdar://problem/41654857>

Reviewers: dblaikie, echristo

Subscribers: kristina, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D59107

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@360221 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/llvm/ExecutionEngine/Orc/IndirectionUtils.h
include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h
include/llvm/Support/Process.h
lib/ExecutionEngine/JITLink/JITLink.cpp
lib/ExecutionEngine/Orc/OrcABISupport.cpp
lib/ExecutionEngine/SectionMemoryManager.cpp
lib/Support/MemoryBuffer.cpp
lib/Support/Unix/Memory.inc
lib/Support/Unix/Path.inc
lib/Support/Unix/Process.inc
lib/Support/Windows/Process.inc
unittests/Support/MemoryTest.cpp

index 2ea9ac1c2b2f9941c037dc6b61fb0303f1d42217..a7ed5372d1e4d0ca079a1fe6c774695af3110308 100644 (file)
@@ -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<uint8_t *>(TrampolineBlock.base());
index 968448112be991c6587b732a0cab5d18f46a3210..4c8e2ea1a7be6bd8064ab34afa794cd9fc594b44 100644 (file)
@@ -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<uint8_t *>(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"
index 9a70304f5c7018fc19cc16e81131429bb914847f..67e37912519bda648bf8c58b0cbf784f5bd82b71 100644 (file)
@@ -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 <system_error>
 
 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<unsigned> 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
index 3169011f08259dfcb4f3f79f3afe539ab30a07d5..1cea043f761334d9c8205487ea1b7e78676c3196 100644 (file)
@@ -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<StringError>("Cannot request higher than page "
                                      "alignment",
                                      inconvertibleErrorCode());
 
-    if (sys::Process::getPageSize() % Seg.getContentAlignment() != 0)
+    if (sys::Process::getPageSizeEstimate() % Seg.getContentAlignment() != 0)
       return make_error<StringError>("Page size is not a multiple of "
                                      "alignment",
                                      inconvertibleErrorCode());
index 4bf52864107b1404df57a46020d040f8f74f027a..8ed23de419d1eef7d8f253c833fbafc5c48ec60c 100644 (file)
@@ -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;
 
index ba277796dd53fc7c25ee1b45576ab3e8da718f1f..2c0cfeb8a9accb3210f5ae657f584d2d50d1244a 100644 (file)
@@ -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);
   }
index 3f13d4d3552adec7ccafee43e67b32ad0520d021..92e39e118b903d8775a489bcac416d7680885058 100644 (file)
@@ -417,7 +417,7 @@ static ErrorOr<std::unique_ptr<MB>>
 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)) {
index b8f5df5f72e99b76dddd978faf27a57f3994cd67..affdb7e70d95203aba28b96682c6bcbc7e8946cb 100644 (file)
@@ -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<uintptr_t>(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();
 
index fb14422ba33af0c3542c8544a76fb89f27a4cbb2..c2f78e79b87687ec92733624ecdf037367ddff73 100644 (file)
@@ -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,
index 7c834f9711469405c932827868e5163eaa2c56b2..78c123493e1db4530a2050ad95b744a4aaf01dc0 100644 (file)
@@ -69,7 +69,7 @@ static std::pair<std::chrono::microseconds, std::chrono::microseconds> getRUsage
 
 // On Cygwin, getpagesize() returns 64k(AllocationGranularity) and
 // offset in mmap(3) should be aligned to the AllocationGranularity.
-unsigned Process::getPageSize() {
+Expected<unsigned> 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<unsigned>(page_size);
 }
 
index b3c9aa0b83cb8d2dbd84582ced5e28915ffa6559..4b91f9f7fc667dce6ffefd2a3edf390cb8df1f04 100644 (file)
@@ -56,7 +56,7 @@ static unsigned computePageSize() {
   return static_cast<unsigned>(info.dwPageSize);
 }
 
-unsigned Process::getPageSize() {
+Expected<unsigned> Process::getPageSize() {
   static unsigned Ret = computePageSize();
   return Ret;
 }
index 33cc3edb815c282f083f9bfd4dac474d873daa83..dc5f606688f9c9326527cf60d274eb71d209c81d 100644 (file)
@@ -50,7 +50,7 @@ class MappedMemoryTest : public ::testing::TestWithParam<unsigned> {
 public:
   MappedMemoryTest() {
     Flags = GetParam();
-    PageSize = sys::Process::getPageSize();
+    PageSize = sys::Process::getPageSizeEstimate();
   }
 
 protected: