Fix test for memory allocators that want to look backwards.
authorPeter Griess <pgriess@fb.com>
Thu, 26 Sep 2013 18:27:05 +0000 (13:27 -0500)
committerPeter Griess <pgriess@fb.com>
Tue, 15 Oct 2013 01:47:17 +0000 (18:47 -0700)
Summary:
- The NeedleFinderTest.NoSegFault test uses mprotect(2) to ensure that
our needle implementations don't peek past the end of memory. However,
some memory allocators (e.g. the defaulton OS X) seem to look at the
last byte of a page. As a result, if we allocate 2 pages and mark the
second as PROT_NONE, then ask the memory allocator for 2 more pages,
it may end up peeking at the last byte of the second page, triggering
a SIGBUS. To work around this, allocate 8 pages of memory and only
mark the second as PROT_NONE.
- Clear mprotect(2) bits before freeing memory.

Test Plan:
- fbconfig -r folly && fbmake runtests
- ./configure && make check on Ubuntu/FC/Mac

Reviewed By: delong.j@fb.com

FB internal diff: D998592

folly/test/RangeTest.cpp

index 445df4248fb324290b594115ab4f7c962beb6302..a6fe97e90da2182ec54329d4c9f01faa34802b48 100644 (file)
@@ -441,8 +441,7 @@ const size_t kPageSize = 4096;
 void createProtectedBuf(StringPiece& contents, char** buf) {
   ASSERT_LE(contents.size(), kPageSize);
   const size_t kSuccess = 0;
-  char* tmp;
-  if (kSuccess != posix_memalign((void**)buf, kPageSize, 2 * kPageSize)) {
+  if (kSuccess != posix_memalign((void**)buf, kPageSize, 4 * kPageSize)) {
     ASSERT_FALSE(true);
   }
   mprotect(*buf + kPageSize, kPageSize, PROT_NONE);
@@ -451,6 +450,11 @@ void createProtectedBuf(StringPiece& contents, char** buf) {
   contents.reset(*buf + newBegin, contents.size());
 }
 
+void freeProtectedBuf(char* buf) {
+  mprotect(buf + kPageSize, kPageSize, PROT_READ | PROT_WRITE);
+  free(buf);
+}
+
 TYPED_TEST(NeedleFinderTest, NoSegFault) {
   const string base = string(32, 'a') + string("b");
   const string delims = string(32, 'c') + string("b");
@@ -482,8 +486,8 @@ TYPED_TEST(NeedleFinderTest, NoSegFault) {
                                      s1.begin(), s1.end());
         auto e2 = (f2 == s2.end()) ? StringPiece::npos : f2 - s2.begin();
         EXPECT_EQ(r2, e2);
-        free(buf1);
-        free(buf2);
+        freeProtectedBuf(buf1);
+        freeProtectedBuf(buf2);
       }
     }
   }