Bug 827150 - Notify ASan/Valgrind when moving entries in and out of a PresArena free list. r=roc,choller
authorMats Palmgren <matspal@gmail.com>
Sun, 03 Feb 2013 02:04:29 +0100
changeset 130564 b2f1089d6cd48473262e9af39cc822fc1f1e8139
parent 130563 83be9ac1f2ebc036d5ad5ce00db515fb3efeb29d
child 130565 f9f36de41b0e8bdb95662f5bfc4ba3d582903580
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, choller
bugs827150
milestone21.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 827150 - Notify ASan/Valgrind when moving entries in and out of a PresArena free list. r=roc,choller
layout/base/nsPresArena.cpp
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -20,16 +20,33 @@
 #include "nsPrintfCString.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
 #endif
 
 #include "mozilla/StandardInteger.h"
 
+#if defined(MOZ_ASAN)
+// XXX These come from sanitizer/asan_interface.h but that header doesn't seem
+// to be installed by default?
+extern "C" {
+  void __asan_poison_memory_region(void const volatile *addr, size_t size)
+    __attribute__((visibility("default")));
+  void __asan_unpoison_memory_region(void const volatile *addr, size_t size)
+    __attribute__((visibility("default")));
+#define ASAN_POISON_MEMORY_REGION(addr, size)   \
+  __asan_poison_memory_region((addr), (size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+  __asan_unpoison_memory_region((addr), (size))
+}
+#elif defined(MOZ_VALGRIND)
+#include "valgrind/memcheck.h"
+#endif
+
 // Even on 32-bit systems, we allocate objects from the frame arena
 // that require 8-byte alignment.  The cast to uintptr_t is needed
 // because plarena isn't as careful about mask construction as it
 // ought to be.
 #define ALIGN_SHIFT 3
 #define PL_ARENA_CONST_ALIGN_MASK ((uintptr_t(1) << ALIGN_SHIFT) - 1)
 #include "plarena.h"
 
@@ -280,18 +297,38 @@ struct nsPresArena::State {
 
   State()
   {
     mFreeLists.Init();
     PL_INIT_ARENA_POOL(&mPool, "PresArena", ARENA_PAGE_SIZE);
     PR_CallOnce(&ARENA_POISON_guard, ARENA_POISON_init);
   }
 
+#if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
+  static PLDHashOperator UnpoisonFreeList(FreeList* aEntry, void*)
+  {
+    nsTArray<void*>::index_type len;
+    while ((len = aEntry->mEntries.Length())) {
+      void* result = aEntry->mEntries.ElementAt(len - 1);
+      aEntry->mEntries.RemoveElementAt(len - 1);
+#if defined(MOZ_ASAN)
+      ASAN_UNPOISON_MEMORY_REGION(result, aEntry->mEntrySize);
+#elif defined(MOZ_VALGRIND)
+      VALGRIND_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
+#endif
+    }
+    return PL_DHASH_NEXT;
+  }
+#endif
+
   ~State()
   {
+#if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
+    mFreeLists.EnumerateEntries(UnpoisonFreeList, nullptr);
+#endif
     PL_FinishArenaPool(&mPool);
   }
 
   void* Allocate(uint32_t aCode, size_t aSize)
   {
     NS_ABORT_IF_FALSE(aSize > 0, "PresArena cannot allocate zero bytes");
 
     // We only hand out aligned sizes
@@ -310,17 +347,21 @@ struct nsPresArena::State {
                         "different sizes for same object type code");
     }
 
     void* result;
     if (len > 0) {
       // LIFO behavior for best cache utilization
       result = list->mEntries.ElementAt(len - 1);
       list->mEntries.RemoveElementAt(len - 1);
-#ifdef DEBUG
+#if defined(MOZ_ASAN)
+      ASAN_UNPOISON_MEMORY_REGION(result, list->mEntrySize);
+#elif defined(MOZ_VALGRIND)
+      VALGRIND_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
+#elif defined(DEBUG)
       {
         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,
                             nsPrintfCString("PresArena: poison overwritten; "
                                             "wanted %.16llx "
@@ -353,16 +394,21 @@ struct nsPresArena::State {
     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;
     }
 
+#if defined(MOZ_ASAN)
+    ASAN_POISON_MEMORY_REGION(aPtr, list->mEntrySize);
+#elif defined(MOZ_VALGRIND)
+    VALGRIND_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
+#endif
     list->mEntries.AppendElement(aPtr);
   }
 
   static size_t SizeOfFreeListEntryExcludingThis(FreeList* aEntry,
                                                  nsMallocSizeOfFun aMallocSizeOf,
                                                  void *)
   {
     return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);