Bug 867530 - Move PresArena poisoning code to MFBT. r=roc
authorMats Palmgren <matspal@gmail.com>
Tue, 07 May 2013 20:48:59 +0200
changeset 142104 35deab0191354fd4c04f45ec5ad025fa31c20f0f
parent 142103 aa00d8de9a795659fd5a73262183e472ae2c58c5
child 142105 69c5ebd945de2e5a33f57211d87ca02acc783b3e
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs867530
milestone23.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 867530 - Move PresArena poisoning code to MFBT. r=roc
layout/base/nsPresArena.cpp
layout/base/nsPresArena.h
layout/base/tests/cpp-tests/Makefile.in
layout/base/tests/cpp-tests/TestPoisonArea.cpp
layout/base/tests/cpp-tests/moz.build
layout/base/tests/moz.build
mfbt/Poison.cpp
mfbt/Poison.h
mfbt/exported_headers.mk
mfbt/sources.mk
mfbt/tests/Makefile.in
mfbt/tests/TestPoisonArea.cpp
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -13,238 +13,30 @@
 // ought to be.
 #define ALIGN_SHIFT 3
 #define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
 #include "plarena.h"
 // plarena.h needs to be included first to make it use the above
 // PL_ARENA_CONST_ALIGN_MASK in this file.
 
 #include "nsPresArena.h"
+
+#include "mozilla/Poison.h"
 #include "nsCRT.h"
 #include "nsDebug.h"
-#include "prinit.h"
 #include "nsArenaMemoryStats.h"
-#include "nsCOMPtr.h"
-#include "nsServiceManagerUtils.h"
 #include "nsPrintfCString.h"
 
-#ifdef MOZ_CRASHREPORTER
-#include "nsICrashReporter.h"
-#endif
-
-#ifdef _WIN32
-# include <windows.h>
-#elif !defined(__OS2__)
-# include <unistd.h>
-# include <sys/mman.h>
-# ifndef MAP_ANON
-#  ifdef MAP_ANONYMOUS
-#   define MAP_ANON MAP_ANONYMOUS
-#  else
-#   error "Don't know how to get anonymous memory"
-#  endif
-# endif
-#endif
-
 // Size to use for PLArena block allocations.
 static const size_t ARENA_PAGE_SIZE = 8192;
 
-// Freed memory is filled with a poison value, which we arrange to
-// form a pointer either to an always-unmapped region of the address
-// space, or to a page that has been reserved and rendered
-// inaccessible via OS primitives.  See tests/TestPoisonArea.cpp for
-// extensive discussion of the requirements for this page.  The code
-// from here to 'class FreeList' needs to be kept in sync with that
-// file.
-
-#ifdef _WIN32
-static void *
-ReserveRegion(uintptr_t region, uintptr_t size)
-{
-  return VirtualAlloc((void *)region, size, MEM_RESERVE, PAGE_NOACCESS);
-}
-
-static void
-ReleaseRegion(void *region, uintptr_t size)
-{
-  VirtualFree(region, size, MEM_RELEASE);
-}
-
-static bool
-ProbeRegion(uintptr_t region, uintptr_t size)
-{
-  SYSTEM_INFO sinfo;
-  GetSystemInfo(&sinfo);
-  if (region >= (uintptr_t)sinfo.lpMaximumApplicationAddress &&
-      region + size >= (uintptr_t)sinfo.lpMaximumApplicationAddress) {
-    return true;
-  } else {
-    return false;
-  }
-}
-
-static uintptr_t
-GetDesiredRegionSize()
-{
-  SYSTEM_INFO sinfo;
-  GetSystemInfo(&sinfo);
-  return sinfo.dwAllocationGranularity;
-}
-
-#define RESERVE_FAILED 0
-
-#elif defined(__OS2__)
-static void *
-ReserveRegion(uintptr_t region, uintptr_t size)
-{
-  // OS/2 doesn't support allocation at an arbitrary address,
-  // so return an address that is known to be invalid.
-  return (void*)0xFFFD0000;
-}
-
-static void
-ReleaseRegion(void *region, uintptr_t size)
-{
-  return;
-}
-
-static bool
-ProbeRegion(uintptr_t region, uintptr_t size)
-{
-  // There's no reliable way to probe an address in the system
-  // arena other than by touching it and seeing if a trap occurs.
-  return false;
-}
-
-static uintptr_t
-GetDesiredRegionSize()
-{
-  // Page size is fixed at 4k.
-  return 0x1000;
-}
-
-#define RESERVE_FAILED 0
-
-#else // Unix
-
-static void *
-ReserveRegion(uintptr_t region, uintptr_t size)
-{
-  return mmap(reinterpret_cast<void*>(region), size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
-}
-
-static void
-ReleaseRegion(void *region, uintptr_t size)
-{
-  munmap(region, size);
-}
-
-static bool
-ProbeRegion(uintptr_t region, uintptr_t size)
-{
-  if (madvise(reinterpret_cast<void*>(region), size, MADV_NORMAL)) {
-    return true;
-  } else {
-    return false;
-  }
-}
-
-static uintptr_t
-GetDesiredRegionSize()
-{
-  return sysconf(_SC_PAGESIZE);
-}
-
-#define RESERVE_FAILED MAP_FAILED
-
-#endif // system dependencies
-
-PR_STATIC_ASSERT(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8);
-PR_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(void *));
-
-static uintptr_t
-ReservePoisonArea(uintptr_t rgnsize)
-{
-  if (sizeof(uintptr_t) == 8) {
-    // Use the hardware-inaccessible region.
-    // We have to avoid 64-bit constants and shifts by 32 bits, since this
-    // code is compiled in 32-bit mode, although it is never executed there.
-    return
-      (((uintptr_t(0x7FFFFFFFu) << 31) << 1 | uintptr_t(0xF0DEAFFFu))
-       & ~(rgnsize-1));
-
-  } else {
-    // First see if we can allocate the preferred poison address from the OS.
-    uintptr_t candidate = (0xF0DEAFFF & ~(rgnsize-1));
-    void *result = ReserveRegion(candidate, rgnsize);
-    if (result == (void *)candidate) {
-      // success - inaccessible page allocated
-      return candidate;
-    }
-
-    // That didn't work, so see if the preferred address is within a range
-    // of permanently inacessible memory.
-    if (ProbeRegion(candidate, rgnsize)) {
-      // success - selected page cannot be usable memory
-      if (result != RESERVE_FAILED)
-        ReleaseRegion(result, rgnsize);
-      return candidate;
-    }
-
-    // The preferred address is already in use.  Did the OS give us a
-    // consolation prize?
-    if (result != RESERVE_FAILED) {
-      return uintptr_t(result);
-    }
-
-    // It didn't, so try to allocate again, without any constraint on
-    // the address.
-    result = ReserveRegion(0, rgnsize);
-    if (result != RESERVE_FAILED) {
-      return uintptr_t(result);
-    }
-
-    NS_RUNTIMEABORT("no usable poison region identified");
-    return 0;
-  }
-}
-
-static uintptr_t ARENA_POISON;
-static PRCallOnceType ARENA_POISON_guard;
-
-static PRStatus
-ARENA_POISON_init()
-{
-  uintptr_t rgnsize = GetDesiredRegionSize();
-  uintptr_t rgnbase = ReservePoisonArea(rgnsize);
-
-  if (rgnsize == 0) // can't happen
-    return PR_FAILURE;
-
-  ARENA_POISON = rgnbase + rgnsize/2 - 1;
-
-#ifdef MOZ_CRASHREPORTER
-  nsCOMPtr<nsICrashReporter> cr =
-    do_GetService("@mozilla.org/toolkit/crash-reporter;1");
-  bool enabled;
-  if (cr && NS_SUCCEEDED(cr->GetEnabled(&enabled)) && enabled) {
-    cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"),
-                            nsPrintfCString("%.16llx", uint64_t(rgnbase)));
-    cr->AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"),
-                            nsPrintfCString("%lu", uint32_t(rgnsize)));
-  }
-#endif
-  return PR_SUCCESS;
-}
-
 nsPresArena::nsPresArena()
 {
   mFreeLists.Init();
   PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
-  PR_CallOnce(&ARENA_POISON_guard, ARENA_POISON_init);
 }
 
 nsPresArena::~nsPresArena()
 {
 #if defined(MOZ_HAVE_MEM_CHECKS)
   mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
 #endif
   PL_FinishArenaPool(&mPool);
@@ -278,24 +70,24 @@ nsPresArena::Allocate(uint32_t aCode, si
     list->mEntries.RemoveElementAt(len - 1);
 #if defined(DEBUG)
     {
       MOZ_MAKE_MEM_DEFINED(result, list->mEntrySize);
       char* p = reinterpret_cast<char*>(result);
       char* limit = p + list->mEntrySize;
       for (; p < limit; p += sizeof(uintptr_t)) {
         uintptr_t val = *reinterpret_cast<uintptr_t*>(p);
-        NS_ABORT_IF_FALSE(val == ARENA_POISON,
+        NS_ABORT_IF_FALSE(val == mozPoisonValue(),
                           nsPrintfCString("PresArena: poison overwritten; "
                                           "wanted %.16llx "
                                           "found %.16llx "
                                           "errors in bits %.16llx",
-                                          uint64_t(ARENA_POISON),
+                                          uint64_t(mozPoisonValue()),
                                           uint64_t(val),
-                                          uint64_t(ARENA_POISON ^ val)
+                                          uint64_t(mozPoisonValue() ^ val)
                                           ).get());
       }
     }
 #endif
     MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
     return result;
   }
 
@@ -314,17 +106,17 @@ nsPresArena::Free(uint32_t aCode, void* 
   // Try to recycle this entry.
   FreeList* list = mFreeLists.GetEntry(aCode);
   NS_ABORT_IF_FALSE(list, "no free list for pres arena object");
   NS_ABORT_IF_FALSE(list->mEntrySize > 0, "PresArena cannot free zero bytes");
 
   char* p = reinterpret_cast<char*>(aPtr);
   char* limit = p + list->mEntrySize;
   for (; p < limit; p += sizeof(uintptr_t)) {
-    *reinterpret_cast<uintptr_t*>(p) = ARENA_POISON;
+    *reinterpret_cast<uintptr_t*>(p) = mozPoisonValue();
   }
 
   MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
   list->mEntries.AppendElement(aPtr);
 }
 
 /* static */ size_t
 nsPresArena::SizeOfFreeListEntryExcludingThis(
@@ -408,14 +200,8 @@ nsPresArena::SizeOfExcludingThis(nsMallo
   size_t mallocSize = PL_SizeOfArenaPoolExcludingPool(&mPool, aMallocSizeOf);
   mallocSize += mFreeLists.SizeOfExcludingThis(SizeOfFreeListEntryExcludingThis,
                                                aMallocSizeOf);
 
   EnumerateData data = { aArenaStats, 0 };
   mFreeLists.EnumerateEntries(FreeListEnumerator, &data);
   aArenaStats->mOther = mallocSize - data.total;
 }
-
-/* static */ uintptr_t
-nsPresArena::GetPoisonValue()
-{
-  return ARENA_POISON;
-}
--- a/layout/base/nsPresArena.h
+++ b/layout/base/nsPresArena.h
@@ -82,25 +82,16 @@ public:
 
   /**
    * Fill aArenaStats with sizes of interesting objects allocated in
    * this arena and its mOther field with the size of everything else.
    */
   void SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf,
                            nsArenaMemoryStats* aArenaStats);
 
-  /**
-   * Get the poison value that can be used to fill a memory space with
-   * an address that leads to a safe crash when dereferenced.
-   *
-   * The caller is responsible for ensuring that a pres shell has been
-   * initialized before calling this.
-   */
-  static uintptr_t GetPoisonValue();
-
 private:
   NS_HIDDEN_(void*) Allocate(uint32_t aCode, size_t aSize);
   NS_HIDDEN_(void) Free(uint32_t aCode, void* aPtr);
 
   // All keys to this hash table fit in 32 bits (see below) so we do not
   // bother actually hashing them.
   class FreeList : public PLDHashEntryHdr
   {
deleted file mode 100644
--- a/layout/base/tests/cpp-tests/Makefile.in
+++ /dev/null
@@ -1,22 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-DEPTH := @DEPTH@
-topsrcdir := @top_srcdir@
-srcdir := @srcdir@
-VPATH := @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-CPP_UNIT_TESTS := \
-  $(NULL)
-
-# These tests don't work with AddressSanitizer enabled
-ifndef MOZ_ASAN
-CPP_UNIT_TESTS += \
-  TestPoisonArea.cpp \
-  $(NULL)
-endif
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/layout/base/tests/cpp-tests/moz.build
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
--- a/layout/base/tests/moz.build
+++ b/layout/base/tests/moz.build
@@ -1,8 +1,7 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 TEST_DIRS += ['chrome']
-TEST_TOOL_DIRS += ['cpp-tests']
new file mode 100644
--- /dev/null
+++ b/mfbt/Poison.cpp
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A poison value that can be used to fill a memory space with
+ * an address that leads to a safe crash when dereferenced.
+ */
+
+#include "mozilla/Poison.h"
+
+#include "mozilla/Assertions.h"
+#ifdef _WIN32
+# include <windows.h>
+#elif !defined(__OS2__)
+# include <unistd.h>
+# include <sys/mman.h>
+# ifndef MAP_ANON
+#  ifdef MAP_ANONYMOUS
+#   define MAP_ANON MAP_ANONYMOUS
+#  else
+#   error "Don't know how to get anonymous memory"
+#  endif
+# endif
+#endif
+
+extern "C" {
+uintptr_t gMozillaPoisonValue;
+uintptr_t gMozillaPoisonBase;
+uintptr_t gMozillaPoisonSize;
+}
+
+// Freed memory is filled with a poison value, which we arrange to
+// form a pointer either to an always-unmapped region of the address
+// space, or to a page that has been reserved and rendered
+// inaccessible via OS primitives.  See tests/TestPoisonArea.cpp for
+// extensive discussion of the requirements for this page.  The code
+// from here to 'class FreeList' needs to be kept in sync with that
+// file.
+
+#ifdef _WIN32
+static void *
+ReserveRegion(uintptr_t region, uintptr_t size)
+{
+  return VirtualAlloc((void *)region, size, MEM_RESERVE, PAGE_NOACCESS);
+}
+
+static void
+ReleaseRegion(void *region, uintptr_t size)
+{
+  VirtualFree(region, size, MEM_RELEASE);
+}
+
+static bool
+ProbeRegion(uintptr_t region, uintptr_t size)
+{
+  SYSTEM_INFO sinfo;
+  GetSystemInfo(&sinfo);
+  if (region >= (uintptr_t)sinfo.lpMaximumApplicationAddress &&
+      region + size >= (uintptr_t)sinfo.lpMaximumApplicationAddress) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static uintptr_t
+GetDesiredRegionSize()
+{
+  SYSTEM_INFO sinfo;
+  GetSystemInfo(&sinfo);
+  return sinfo.dwAllocationGranularity;
+}
+
+#define RESERVE_FAILED 0
+
+#elif defined(__OS2__)
+static void *
+ReserveRegion(uintptr_t region, uintptr_t size)
+{
+  // OS/2 doesn't support allocation at an arbitrary address,
+  // so return an address that is known to be invalid.
+  return (void*)0xFFFD0000;
+}
+
+static void
+ReleaseRegion(void *region, uintptr_t size)
+{
+  return;
+}
+
+static bool
+ProbeRegion(uintptr_t region, uintptr_t size)
+{
+  // There's no reliable way to probe an address in the system
+  // arena other than by touching it and seeing if a trap occurs.
+  return false;
+}
+
+static uintptr_t
+GetDesiredRegionSize()
+{
+  // Page size is fixed at 4k.
+  return 0x1000;
+}
+
+#define RESERVE_FAILED 0
+
+#else // Unix
+
+static void *
+ReserveRegion(uintptr_t region, uintptr_t size)
+{
+  return mmap(reinterpret_cast<void*>(region), size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0);
+}
+
+static void
+ReleaseRegion(void *region, uintptr_t size)
+{
+  munmap(region, size);
+}
+
+static bool
+ProbeRegion(uintptr_t region, uintptr_t size)
+{
+  if (madvise(reinterpret_cast<void*>(region), size, MADV_NORMAL)) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static uintptr_t
+GetDesiredRegionSize()
+{
+  return sysconf(_SC_PAGESIZE);
+}
+
+#define RESERVE_FAILED MAP_FAILED
+
+#endif // system dependencies
+
+MOZ_STATIC_ASSERT(sizeof(uintptr_t) == 4 || sizeof(uintptr_t) == 8, "");
+MOZ_STATIC_ASSERT(sizeof(uintptr_t) == sizeof(void *), "");
+
+static uintptr_t
+ReservePoisonArea(uintptr_t rgnsize)
+{
+  if (sizeof(uintptr_t) == 8) {
+    // Use the hardware-inaccessible region.
+    // We have to avoid 64-bit constants and shifts by 32 bits, since this
+    // code is compiled in 32-bit mode, although it is never executed there.
+    return
+      (((uintptr_t(0x7FFFFFFFu) << 31) << 1 | uintptr_t(0xF0DEAFFFu))
+       & ~(rgnsize-1));
+
+  } else {
+    // First see if we can allocate the preferred poison address from the OS.
+    uintptr_t candidate = (0xF0DEAFFF & ~(rgnsize-1));
+    void *result = ReserveRegion(candidate, rgnsize);
+    if (result == (void *)candidate) {
+      // success - inaccessible page allocated
+      return candidate;
+    }
+
+    // That didn't work, so see if the preferred address is within a range
+    // of permanently inacessible memory.
+    if (ProbeRegion(candidate, rgnsize)) {
+      // success - selected page cannot be usable memory
+      if (result != RESERVE_FAILED)
+        ReleaseRegion(result, rgnsize);
+      return candidate;
+    }
+
+    // The preferred address is already in use.  Did the OS give us a
+    // consolation prize?
+    if (result != RESERVE_FAILED) {
+      return uintptr_t(result);
+    }
+
+    // It didn't, so try to allocate again, without any constraint on
+    // the address.
+    result = ReserveRegion(0, rgnsize);
+    if (result != RESERVE_FAILED) {
+      return uintptr_t(result);
+    }
+
+    // no usable poison region identified
+    MOZ_CRASH();
+    return 0;
+  }
+}
+
+void
+mozPoisonValueInit()
+{
+  gMozillaPoisonSize = GetDesiredRegionSize();
+  gMozillaPoisonBase = ReservePoisonArea(gMozillaPoisonSize);
+
+  if (gMozillaPoisonSize == 0) // can't happen
+    return;
+
+  gMozillaPoisonValue = gMozillaPoisonBase + gMozillaPoisonSize/2 - 1;
+}
new file mode 100644
--- /dev/null
+++ b/mfbt/Poison.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * A poison value that can be used to fill a memory space with
+ * an address that leads to a safe crash when dereferenced.
+ */
+
+#ifndef mozilla_Poison_h_
+#define mozilla_Poison_h_
+
+#include "mozilla/Assertions.h"
+#include "mozilla/StandardInteger.h"
+#include "mozilla/Types.h"
+
+MOZ_BEGIN_EXTERN_C
+
+extern MFBT_DATA uintptr_t gMozillaPoisonValue;
+
+/**
+ * @return the poison value.
+ */
+inline uintptr_t mozPoisonValue()
+{
+  return gMozillaPoisonValue;
+}
+
+/**
+ * Overwrite the memory block of aSize bytes at aPtr with the poison value.
+ * aPtr MUST be aligned at a sizeof(uintptr_t) boundary.
+ * Only an even number of sizeof(uintptr_t) bytes are overwritten, the last
+ * few bytes (if any) is not overwritten.
+ */
+inline void mozWritePoison(void* aPtr, size_t aSize)
+{
+  MOZ_ASSERT((uintptr_t)aPtr % sizeof(uintptr_t) == 0, "bad alignment");
+  MOZ_ASSERT(aSize >= sizeof(uintptr_t), "poisoning this object has no effect");
+  const uintptr_t POISON = mozPoisonValue();
+  char* p = (char*)aPtr;
+  char* limit = p + aSize;
+  for (; p < limit; p += sizeof(uintptr_t)) {
+    *((uintptr_t*)p) = POISON;
+  }
+}
+
+/**
+ * Initialize the poison value.
+ * This should only be called once.
+ */
+extern MFBT_API void mozPoisonValueInit();
+
+/* Values annotated by CrashReporter */
+extern MFBT_DATA uintptr_t gMozillaPoisonBase;
+extern MFBT_DATA uintptr_t gMozillaPoisonSize;
+
+MOZ_END_EXTERN_C
+
+#endif /* mozilla_Poison_h_ */
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -26,16 +26,17 @@ EXPORTS_mozilla += \
   HashFunctions.h \
   Likely.h \
   LinkedList.h \
   MathAlgorithms.h \
   MemoryChecking.h \
   MSStdInt.h \
   NullPtr.h \
   PodOperations.h \
+  Poison.h \
   Range.h \
   RangedPtr.h \
   RefPtr.h \
   Scoped.h \
   SHA1.h \
   SplayTree.h \
   StandardInteger.h \
   ThreadLocal.h \
--- a/mfbt/sources.mk
+++ b/mfbt/sources.mk
@@ -4,16 +4,17 @@
 
 ifndef MFBT_ROOT
 $(error Before including this file, you must define MFBT_ROOT to point to \
 the MFBT source directory)
 endif
 
 CPPSRCS += \
   HashFunctions.cpp \
+  Poison.cpp \
   SHA1.cpp \
   $(NULL)
 
 # Imported double-conversion sources.
 VPATH += $(MFBT_ROOT)/double-conversion \
   $(NULL)
 
 CPPSRCS += \
--- a/mfbt/tests/Makefile.in
+++ b/mfbt/tests/Makefile.in
@@ -17,16 +17,23 @@ CPP_UNIT_TESTS = \
   TestCheckedInt.cpp \
   TestEndian.cpp \
   TestEnumSet.cpp \
   TestSHA1.cpp \
   TestTypeTraits.cpp \
   TestWeakPtr.cpp \
   $(NULL)
 
+# These tests don't work with AddressSanitizer enabled
+ifndef MOZ_ASAN
+CPP_UNIT_TESTS += \
+  TestPoisonArea.cpp \
+  $(NULL)
+endif
+
 # in order to prevent rules.mk from trying to link to libraries that are
 # not available to MFBT, we have to reset these MOZ_GLUE*_LDFLAGS before including it
 # and LIBS_ after including it. For WRAP_LDFLAGS, it shouldn't matter.
 # See later comments in bug 732875.
 
 MOZ_GLUE_PROGRAM_LDFLAGS=
 MOZ_GLUE_LDFLAGS =
 WRAP_LDFLAGS=
rename from layout/base/tests/cpp-tests/TestPoisonArea.cpp
rename to mfbt/tests/TestPoisonArea.cpp