Rework the de-allocation guard on the munmap implementation
authorChristopher Dykes <cdykes@fb.com>
Tue, 6 Sep 2016 23:22:33 +0000 (16:22 -0700)
committerFacebook Github Bot 4 <facebook-github-bot-4-bot@fb.com>
Tue, 6 Sep 2016 23:23:45 +0000 (16:23 -0700)
Summary:
The previous version assumed that `RegionSize` would always be the full size of the allocation done by `VirtualAlloc`. However, `RegionSize` actually only includes the following pages that have the same attributes, so, if you change the access permissions via `mprotect`, the `RegionSize` would exclude that region, which is not what was intended.
This instead stores the length and a dummy magic value after the end of the requested allocation.

Reviewed By: yfeldblum

Differential Revision: D3812949

fbshipit-source-id: 53bbbcc371accbed08adaffa82fc082ec44f316f

folly/portability/SysMman.cpp

index 38d56ae3bf2be6b20e18046302edad804c9c8d69..844002688a212eaf43917a4a295e4994104e274e 100755 (executable)
@@ -77,6 +77,14 @@ int mlock(const void* addr, size_t len) {
   return 0;
 }
 
+namespace {
+constexpr uint32_t kMMapLengthMagic = 0xFACEB00C;
+struct MemMapDebugTrailer {
+  size_t length;
+  uint32_t magic;
+};
+}
+
 void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
   // Make sure it's something we support first.
 
@@ -128,6 +136,14 @@ void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
     }
     CloseHandle(fmh);
   } else {
+    auto baseLength = length;
+    if (folly::kIsDebug) {
+      // In debug mode we keep track of the length to make
+      // sure you're only munmapping the entire thing if
+      // we're using VirtualAlloc.
+      length += sizeof(MemMapDebugTrailer);
+    }
+
     // VirtualAlloc rounds size down to a multiple
     // of the system allocation granularity :(
     length = alignToAllocationGranularity(length);
@@ -135,6 +151,12 @@ void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t off) {
     if (ret == nullptr) {
       return MAP_FAILED;
     }
+
+    if (folly::kIsDebug) {
+      auto deb = (MemMapDebugTrailer*)((char*)ret + baseLength);
+      deb->length = baseLength;
+      deb->magic = kMMapLengthMagic;
+    }
   }
 
   // TODO: Could technically implement MAP_POPULATE via PrefetchVirtualMemory
@@ -177,8 +199,11 @@ int munmap(void* addr, size_t length) {
       // in debug mode.
       MEMORY_BASIC_INFORMATION inf;
       VirtualQuery(addr, &inf, sizeof(inf));
-      assert(inf.BaseAddress == addr);
-      assert(inf.RegionSize == alignToAllocationGranularity(length));
+      assert(inf.AllocationBase == addr);
+
+      auto deb = (MemMapDebugTrailer*)((char*)addr + length);
+      assert(deb->length == length);
+      assert(deb->magic == kMMapLengthMagic);
     }
     if (!VirtualFree(addr, 0, MEM_RELEASE)) {
       return -1;