Title: [202463] trunk/Source/_javascript_Core
Revision
202463
Author
[email protected]
Date
2016-06-24 17:03:44 -0700 (Fri, 24 Jun 2016)

Log Message

B3 should die sooner if a Value has the wrong number of children
https://bugs.webkit.org/show_bug.cgi?id=159108

Reviewed by Mark Lam.
        
I've been looking at a bug (rdar://problem/26500743) that's about a Vector OOB crash in
ReduceStrength::rangeFor(). The only Vector accesses are to Value::m_children, and all of
the accesses in rangeFor() are for child(0) or child(1) of binary arithmetic opcodes.
Clearly those should never go out-of-bounds.
        
Maybe we have horrible memory corruption. Or maybe some path creates a Value with the
wrong number of children, and that path is not tested by any of our tests. This patch adds
release assertions that will catch the latter.
        
I've tested this a lot. It's not a regression on our benchmarks.

* b3/B3Opcode.h:
* b3/B3Value.cpp:
(JSC::B3::Value::dumpMeta):
(JSC::B3::Value::typeFor):
(JSC::B3::Value::badOpcode):
(JSC::B3::Value::checkOpcode): Deleted.
* b3/B3Value.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (202462 => 202463)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-24 23:54:22 UTC (rev 202462)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-25 00:03:44 UTC (rev 202463)
@@ -1,3 +1,29 @@
+2016-06-24  Filip Pizlo  <[email protected]>
+
+        B3 should die sooner if a Value has the wrong number of children
+        https://bugs.webkit.org/show_bug.cgi?id=159108
+
+        Reviewed by Mark Lam.
+        
+        I've been looking at a bug (rdar://problem/26500743) that's about a Vector OOB crash in
+        ReduceStrength::rangeFor(). The only Vector accesses are to Value::m_children, and all of
+        the accesses in rangeFor() are for child(0) or child(1) of binary arithmetic opcodes.
+        Clearly those should never go out-of-bounds.
+        
+        Maybe we have horrible memory corruption. Or maybe some path creates a Value with the
+        wrong number of children, and that path is not tested by any of our tests. This patch adds
+        release assertions that will catch the latter.
+        
+        I've tested this a lot. It's not a regression on our benchmarks.
+
+        * b3/B3Opcode.h:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::dumpMeta):
+        (JSC::B3::Value::typeFor):
+        (JSC::B3::Value::badOpcode):
+        (JSC::B3::Value::checkOpcode): Deleted.
+        * b3/B3Value.h:
+
 2016-06-24  Mark Lam  <[email protected]>
 
         [JSC] Error prototypes are called on remote scripts.

Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (202462 => 202463)


--- trunk/Source/_javascript_Core/b3/B3Opcode.h	2016-06-24 23:54:22 UTC (rev 202462)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h	2016-06-25 00:03:44 UTC (rev 202463)
@@ -265,7 +265,7 @@
 
 class PrintStream;
 
-void printInternal(PrintStream&, JSC::B3::Opcode);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::B3::Opcode);
 
 } // namespace WTF
 

Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (202462 => 202463)


--- trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-06-24 23:54:22 UTC (rev 202462)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp	2016-06-25 00:03:44 UTC (rev 202463)
@@ -633,25 +633,6 @@
 {
 }
 
-#if !ASSERT_DISABLED
-void Value::checkOpcode(Opcode opcode)
-{
-    ASSERT(!ArgumentRegValue::accepts(opcode));
-    ASSERT(!CCallValue::accepts(opcode));
-    ASSERT(!CheckValue::accepts(opcode));
-    ASSERT(!Const32Value::accepts(opcode));
-    ASSERT(!Const64Value::accepts(opcode));
-    ASSERT(!ConstDoubleValue::accepts(opcode));
-    ASSERT(!ConstFloatValue::accepts(opcode));
-    ASSERT(!ControlValue::accepts(opcode));
-    ASSERT(!MemoryValue::accepts(opcode));
-    ASSERT(!PatchpointValue::accepts(opcode));
-    ASSERT(!SlotBaseValue::accepts(opcode));
-    ASSERT(!UpsilonValue::accepts(opcode));
-    ASSERT(!VariableValue::accepts(opcode));
-}
-#endif // !ASSERT_DISABLED
-
 Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
 {
     switch (opcode) {
@@ -729,6 +710,12 @@
     }
 }
 
+void Value::badOpcode(Opcode opcode, unsigned numArgs)
+{
+    dataLog("Bad opcode ", opcode, " with ", numArgs, " args.\n");
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
 } } // namespace JSC::B3
 
 #endif // ENABLE(B3_JIT)

Modified: trunk/Source/_javascript_Core/b3/B3Value.h (202462 => 202463)


--- trunk/Source/_javascript_Core/b3/B3Value.h	2016-06-24 23:54:22 UTC (rev 202462)
+++ trunk/Source/_javascript_Core/b3/B3Value.h	2016-06-25 00:03:44 UTC (rev 202463)
@@ -235,11 +235,71 @@
     friend class SparseCollection<Value>;
 
     // Checks that this opcode is valid for use with B3::Value.
-#if ASSERT_DISABLED
-    static void checkOpcode(Opcode) { }
-#else
-    static void checkOpcode(Opcode);
-#endif
+    ALWAYS_INLINE static void checkOpcode(Opcode opcode, unsigned numArgs)
+    {
+        switch (opcode) {
+        case FramePointer:
+        case Nop:
+        case Phi:
+            if (UNLIKELY(numArgs))
+                badOpcode(opcode, numArgs);
+            break;
+        case Identity:
+        case Neg:
+        case Clz:
+        case Abs:
+        case Ceil:
+        case Floor:
+        case Sqrt:
+        case SExt8:
+        case SExt16:
+        case Trunc:
+        case SExt32:
+        case ZExt32:
+        case FloatToDouble:
+        case IToD:
+        case DoubleToFloat:
+        case IToF:
+        case BitwiseCast:
+            if (UNLIKELY(numArgs != 1))
+                badOpcode(opcode, numArgs);
+            break;
+        case Add:
+        case Sub:
+        case Mul:
+        case Div:
+        case Mod:
+        case ChillDiv:
+        case ChillMod:
+        case BitAnd:
+        case BitOr:
+        case BitXor:
+        case Shl:
+        case SShr:
+        case ZShr:
+        case Equal:
+        case NotEqual:
+        case LessThan:
+        case GreaterThan:
+        case LessEqual:
+        case GreaterEqual:
+        case Above:
+        case Below:
+        case AboveEqual:
+        case BelowEqual:
+        case EqualOrUnordered:
+            if (UNLIKELY(numArgs != 2))
+                badOpcode(opcode, numArgs);
+            break;
+        case Select:
+            if (UNLIKELY(numArgs != 3))
+                badOpcode(opcode, numArgs);
+            break;
+        default:
+            badOpcode(opcode, numArgs);
+            break;
+        }
+    }
 
 protected:
     enum CheckedOpcodeTag { CheckedOpcode };
@@ -309,11 +369,35 @@
     // This is the constructor you end up actually calling, if you're instantiating Value
     // directly.
     template<typename... Arguments>
-    explicit Value(Opcode opcode, Arguments&&... arguments)
-        : Value(CheckedOpcode, opcode, std::forward<Arguments>(arguments)...)
+        explicit Value(Opcode opcode, Type type, Origin origin)
+        : Value(CheckedOpcode, opcode, type, origin)
     {
-        checkOpcode(opcode);
+        checkOpcode(opcode, 0);
     }
+    template<typename... Arguments>
+        explicit Value(Opcode opcode, Type type, Origin origin, Value* firstChild, Arguments&&... arguments)
+        : Value(CheckedOpcode, opcode, type, origin, firstChild, std::forward<Arguments>(arguments)...)
+    {
+        checkOpcode(opcode, 1 + sizeof...(arguments));
+    }
+    template<typename... Arguments>
+        explicit Value(Opcode opcode, Type type, Origin origin, const AdjacencyList& children)
+        : Value(CheckedOpcode, opcode, type, origin, children)
+    {
+        checkOpcode(opcode, children.size());
+    }
+    template<typename... Arguments>
+        explicit Value(Opcode opcode, Type type, Origin origin, AdjacencyList&& children)
+        : Value(CheckedOpcode, opcode, type, origin, WTFMove(children))
+    {
+        checkOpcode(opcode, m_children.size());
+    }
+    template<typename... Arguments>
+        explicit Value(Opcode opcode, Origin origin, Arguments&&... arguments)
+        : Value(CheckedOpcode, opcode, origin, std::forward<Arguments>(arguments)...)
+    {
+        checkOpcode(opcode, sizeof...(arguments));
+    }
 
 private:
     friend class CheckValue; // CheckValue::convertToAdd() modifies m_opcode.
@@ -330,6 +414,8 @@
     Origin m_origin;
     AdjacencyList m_children;
 
+    JS_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH static void badOpcode(Opcode, unsigned);
+
 public:
     BasicBlock* owner { nullptr }; // computed by Procedure::resetValueOwners().
 };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to