Bug 838557 - Create a common interface for ASan/Valgrind functions. r=mats,bhackett
authorChristian Holler <choller@mozilla.com>
Fri, 15 Feb 2013 00:50:11 +0100
changeset 132645 df6fbdf62e13933bde8593f623306846f0306de5
parent 132644 458969f6b3690ad647f3349b6ff9aaf50e773807
child 132646 c144a6760459e99feb932eb189480d3a0a8de2fe
push id317
push userbbajaj@mozilla.com
push dateTue, 07 May 2013 01:20:33 +0000
treeherdermozilla-release@159a10910249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats, bhackett
bugs838557
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 838557 - Create a common interface for ASan/Valgrind functions. r=mats,bhackett
js/src/ds/LifoAlloc.cpp
js/src/ds/LifoAlloc.h
layout/base/nsPresArena.cpp
mfbt/ASan.h
mfbt/MemoryChecking.h
mfbt/exported_headers.mk
--- a/js/src/ds/LifoAlloc.cpp
+++ b/js/src/ds/LifoAlloc.cpp
@@ -32,21 +32,17 @@ BumpChunk::new_(size_t chunkSize)
 
 void
 BumpChunk::delete_(BumpChunk *chunk)
 {
 #ifdef DEBUG
     // Part of the chunk may have been marked as poisoned/noaccess.  Undo that
     // before writing the 0xcd bytes.
     size_t size = sizeof(*chunk) + chunk->bumpSpaceSize;
-#if defined(MOZ_ASAN)
-    ASAN_UNPOISON_MEMORY_REGION(chunk, size);
-#elif defined(MOZ_VALGRIND)
-    VALGRIND_MAKE_MEM_UNDEFINED(chunk, size);
-#endif
+    MOZ_MAKE_MEM_UNDEFINED(chunk, size);
     memset(chunk, 0xcd, size);
 #endif
     js_free(chunk);
 }
 
 bool
 BumpChunk::canAlloc(size_t n)
 {
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -3,26 +3,22 @@
  *
  * 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/. */
 
 #ifndef LifoAlloc_h__
 #define LifoAlloc_h__
 
-#include "mozilla/ASan.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
+#include "mozilla/MemoryChecking.h"
 #include "mozilla/TypeTraits.h"
 
-#if defined(MOZ_VALGRIND)
-#include "valgrind/memcheck.h"
-#endif
-
 /*
  * This data structure supports stacky LIFO allocation (mark/release and
  * LifoAllocScope). It does not maintain one contiguous segment; instead, it
  * maintains a bunch of linked memory segments. In order to prevent malloc/free
  * thrashing, unused segments are deallocated when garbage collection occurs.
  */
 
 #include "jsutil.h"
@@ -67,39 +63,34 @@ class BumpChunk
         next_(NULL), bumpSpaceSize(bumpSpaceSize)
     {
         JS_ASSERT(bump == AlignPtr(bump));
     }
 
     void setBump(void *ptr) {
         JS_ASSERT(bumpBase() <= ptr);
         JS_ASSERT(ptr <= limit);
-#if defined(DEBUG) || defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
+#if defined(DEBUG) || defined(MOZ_HAVE_MEM_CHECKS)
         char* prevBump = bump;
 #endif
         bump = static_cast<char *>(ptr);
 #ifdef DEBUG
         JS_ASSERT(contains(prevBump));
 
         /* Clobber the now-free space. */
         if (prevBump > bump)
             memset(bump, 0xcd, prevBump - bump);
 #endif
 
         /* Poison/Unpoison memory that we just free'd/allocated */
-#if defined(MOZ_ASAN)
+#if defined(MOZ_HAVE_MEM_CHECKS)
         if (prevBump > bump)
-            ASAN_POISON_MEMORY_REGION(bump, prevBump - bump);
+            MOZ_MAKE_MEM_NOACCESS(bump, prevBump - bump);
         else if (bump > prevBump)
-            ASAN_UNPOISON_MEMORY_REGION(prevBump, bump - prevBump);
-#elif defined(MOZ_VALGRIND)
-        if (prevBump > bump)
-            VALGRIND_MAKE_MEM_NOACCESS(bump, prevBump - bump);
-        else if (bump > prevBump)
-            VALGRIND_MAKE_MEM_UNDEFINED(prevBump, bump - prevBump);
+            MOZ_MAKE_MEM_UNDEFINED(prevBump, bump - prevBump);
 #endif
     }
 
   public:
     BumpChunk *next() const { return next_; }
     void setNext(BumpChunk *succ) { next_ = succ; }
 
     size_t used() const { return bump - bumpBase(); }
--- a/layout/base/nsPresArena.cpp
+++ b/layout/base/nsPresArena.cpp
@@ -19,21 +19,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsPrintfCString.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
 #endif
 
 #include "mozilla/StandardInteger.h"
-#include "mozilla/ASan.h"
-
-#if defined(MOZ_VALGRIND)
-#include "valgrind/memcheck.h"
-#endif
+#include "mozilla/MemoryChecking.h"
 
 // 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"
@@ -285,36 +281,32 @@ 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)
+#if defined(MOZ_HAVE_MEM_CHECKS)
   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
+      MOZ_MAKE_MEM_UNDEFINED(result, aEntry->mEntrySize);
     }
     return PL_DHASH_NEXT;
   }
 #endif
 
   ~State()
   {
-#if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
+#if defined(MOZ_HAVE_MEM_CHECKS)
     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");
@@ -335,21 +327,17 @@ 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);
-#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)
+#if 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 "
@@ -357,16 +345,17 @@ struct nsPresArena::State {
                                             "errors in bits %.16llx",
                                             uint64_t(ARENA_POISON),
                                             uint64_t(val),
                                             uint64_t(ARENA_POISON ^ val)
                                             ).get());
         }
       }
 #endif
+      MOZ_MAKE_MEM_UNDEFINED(result, list->mEntrySize);
       return result;
     }
 
     // Allocate a new chunk from the arena
     list->mEntriesEverAllocated++;
     PL_ARENA_ALLOCATE(result, &mPool, aSize);
     if (!result) {
       NS_RUNTIMEABORT("out of memory");
@@ -382,21 +371,17 @@ 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
+    MOZ_MAKE_MEM_NOACCESS(aPtr, list->mEntrySize);
     list->mEntries.AppendElement(aPtr);
   }
 
   static size_t SizeOfFreeListEntryExcludingThis(FreeList* aEntry,
                                                  nsMallocSizeOfFun aMallocSizeOf,
                                                  void *)
   {
     return aEntry->mEntries.SizeOfExcludingThis(aMallocSizeOf);
deleted file mode 100644
--- a/mfbt/ASan.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-/*
- * Provides ASan (AddressSanitizer) specific functions that are normally
- * provided through the sanitizer/asan_interface.h header installed by ASan.
- */
-
-#ifndef mozilla_ASan_h_
-#define mozilla_ASan_h_
-
-#ifdef MOZ_ASAN
-#include <stddef.h>
-
-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))
-}
-#endif
-
-#endif  /* mozilla_ASan_h_ */
new file mode 100644
--- /dev/null
+++ b/mfbt/MemoryChecking.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/*
+ * Provides a common interface to the ASan (AddressSanitizer) and Valgrind 
+ * functions used to mark memory in certain ways. In detail, the following
+ * three macros are provided:
+ *
+ *   MOZ_MAKE_MEM_NOACCESS  - Mark memory as unsafe to access (e.g. freed)
+ *   MOZ_MAKE_MEM_UNDEFINED - Mark memory as accessible, with content undefined
+ *   MOZ_MAKE_MEM_DEFINED - Mark memory as accessible, with content defined
+ *
+ * With Valgrind in use, these directly map to the three respective Valgrind
+ * macros. With ASan in use, the NOACCESS macro maps to poisoning the memory,
+ * while the UNDEFINED/DEFINED macros unpoison memory.
+ *
+ * With no memory checker available, all macros expand to the empty statement.
+ */
+
+#ifndef mozilla_MemoryChecking_h_
+#define mozilla_MemoryChecking_h_
+
+#if defined(MOZ_VALGRIND)
+#include "valgrind/memcheck.h"
+#endif
+
+#if defined(MOZ_ASAN) || defined(MOZ_VALGRIND)
+#define MOZ_HAVE_MEM_CHECKS 1
+#endif
+
+#if defined(MOZ_ASAN)
+#include <stddef.h>
+
+extern "C" {
+  /* These definitions are usually provided through the 
+   * sanitizer/asan_interface.h header installed by ASan.
+   */
+  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 MOZ_MAKE_MEM_NOACCESS(addr, size) \
+  __asan_poison_memory_region((addr), (size))
+
+#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
+  __asan_unpoison_memory_region((addr), (size))
+
+#define MOZ_MAKE_MEM_DEFINED(addr, size) \
+  __asan_unpoison_memory_region((addr), (size))
+}
+#elif defined(MOZ_VALGRIND)
+#define MOZ_MAKE_MEM_NOACCESS(addr, size) \
+  VALGRIND_MAKE_MEM_NOACCESS((addr), (size))
+
+#define MOZ_MAKE_MEM_UNDEFINED(addr, size) \
+  VALGRIND_MAKE_MEM_UNDEFINED((addr), (size))
+
+#define MOZ_MAKE_MEM_DEFINED(addr, size) \
+  VALGRIND_MAKE_MEM_DEFINED((addr), (size))
+#else
+
+#define MOZ_MAKE_MEM_NOACCESS(addr, size) do {} while(0)
+#define MOZ_MAKE_MEM_UNDEFINED(addr, size) do {} while(0)
+#define MOZ_MAKE_MEM_DEFINED(addr, size) do {} while(0)
+
+#endif
+
+#endif  /* mozilla_MemoryChecking_h_ */
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -4,32 +4,32 @@
 
 # This file defines the headers exported by mfbt.  It is included by mfbt
 # itself and by the JS engine, which, when built standalone, must install
 # mfbt's exported headers itself.
 
 EXPORTS_NAMESPACES += mozilla
 
 EXPORTS_mozilla += \
-  ASan.h \
   Assertions.h \
   Attributes.h \
   BloomFilter.h \
   Char16.h \
   CheckedInt.h \
   Compiler.h \
   Constants.h \
   DebugOnly.h \
   EnumSet.h \
   FloatingPoint.h \
   GuardObjects.h \
   HashFunctions.h \
   Likely.h \
   LinkedList.h \
   MathAlgorithms.h \
+  MemoryChecking.h \
   MSStdInt.h \
   NullPtr.h \
   Range.h \
   RangedPtr.h \
   RefPtr.h \
   Scoped.h \
   SHA1.h \
   SplayTree.h \