Bug 1153382 - Make poison values more toxic when used as a Value; r=sfink
☠☠ backed out by c8ef1b55f785 ☠ ☠
authorTerrence Cole <terrence@mozilla.com>
Mon, 13 Apr 2015 09:56:02 -0700
changeset 258329 42ed856b37d93aedc448585c50fc89dcb063be10
parent 258328 bbfa03945585e60ac1bafee72190562b6acba697
child 258330 a54ea61e6fc4d30494497e34aacae735cf3b8dcc
push id8007
push userraliiev@mozilla.com
push dateMon, 11 May 2015 19:23:16 +0000
treeherdermozilla-aurora@e2ce1aac996e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1153382
milestone40.0a1
Bug 1153382 - Make poison values more toxic when used as a Value; r=sfink
js/src/jsutil.h
mfbt/PodOperations.h
--- a/js/src/jsutil.h
+++ b/js/src/jsutil.h
@@ -9,20 +9,22 @@
  */
 
 #ifndef jsutil_h
 #define jsutil_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/GuardObjects.h"
+#include "mozilla/PodOperations.h"
 
 #include <limits.h>
 
 #include "js/Utility.h"
+#include "js/Value.h"
 
 #define JS_ALWAYS_TRUE(expr)      MOZ_ALWAYS_TRUE(expr)
 #define JS_ALWAYS_FALSE(expr)     MOZ_ALWAYS_FALSE(expr)
 
 #if defined(JS_DEBUG)
 # define JS_DIAGNOSTICS_ASSERT(expr) MOZ_ASSERT(expr)
 #elif defined(JS_CRASH_DIAGNOSTICS)
 # define JS_DIAGNOSTICS_ASSERT(expr) do { if (MOZ_UNLIKELY(!(expr))) MOZ_CRASH(); } while(0)
@@ -273,30 +275,41 @@ ClearAllBitArrayElements(size_t* array, 
 {
     for (unsigned i = 0; i < length; ++i)
         array[i] = 0;
 }
 
 }  /* namespace js */
 
 static inline void*
-Poison(void* ptr, int value, size_t num)
+Poison(void* ptr, uint8_t value, size_t num)
 {
-    static bool inited = false;
-    static bool poison = true;
-    if (!inited) {
-        char* env = getenv("JSGC_DISABLE_POISONING");
-        if (env)
-            poison = false;
-        inited = true;
+    static bool poison = getenv("JSGC_DISABLE_POISONING");
+    if (poison) {
+        // Without a valid Value tag, a poisoned Value may look like a valid
+        // floating point number. To ensure that we crash more readily when
+        // observing a poisoned Value, we make the poison an invalid ObjectValue.
+        uintptr_t obj;
+        memset(&obj, value, sizeof(obj));
+#if defined(JS_PUNBOX64)
+        obj >>= JSVAL_TAG_SHIFT;
+#endif
+        jsval_layout layout = OBJECT_TO_JSVAL_IMPL((JSObject*)obj);
+
+        size_t value_count = num / sizeof(jsval_layout);
+        size_t byte_count = num % sizeof(jsval_layout);
+        mozilla::PodSet((jsval_layout*)ptr, layout, value_count);
+        if (byte_count) {
+            uint8_t* bytes = static_cast<uint8_t*>(ptr);
+            uint8_t* end = bytes + num;
+            mozilla::PodSet(end - byte_count, value, byte_count);
+        }
+        return ptr;
     }
 
-    if (poison)
-        return memset(ptr, value, num);
-
     return nullptr;
 }
 
 /* Crash diagnostics */
 #if defined(DEBUG) && !defined(MOZ_ASAN)
 # define JS_CRASH_DIAGNOSTICS 1
 #endif
 #if defined(JS_CRASH_DIAGNOSTICS) || defined(JS_GC_ZEAL)
--- a/mfbt/PodOperations.h
+++ b/mfbt/PodOperations.h
@@ -84,16 +84,28 @@ PodAssign(T* aDst, const T* aSrc)
 {
   MOZ_ASSERT(aDst + 1 <= aSrc || aSrc + 1 <= aDst,
              "destination and source must not overlap");
   memcpy(reinterpret_cast<char*>(aDst), reinterpret_cast<const char*>(aSrc),
          sizeof(T));
 }
 
 /**
+ * Set the first |aNElem| T elements in |aDst| to |aSrc|.
+ */
+template<typename T>
+static MOZ_ALWAYS_INLINE void
+PodSet(T* aDst, T aSrc, size_t aNElem)
+{
+  for (const T* dstend = aDst + aNElem; aDst < dstend; aDst++) {
+    *aDst = aSrc;
+  }
+}
+
+/**
  * Copy |aNElem| T elements from |aSrc| to |aDst|.  The two memory ranges must
  * not overlap!
  */
 template<typename T>
 static MOZ_ALWAYS_INLINE void
 PodCopy(T* aDst, const T* aSrc, size_t aNElem)
 {
   MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst,