Reviewers: ulan,

Description:
Add --trace-array-abuse to help find OOB accesses.

[email protected]


Please review this at https://codereview.chromium.org/12220040/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  M src/elements.h
  M src/elements.cc
  M src/flag-definitions.h
  M src/objects.cc
  M test/mjsunit/compiler/array-access.js


Index: src/elements.cc
diff --git a/src/elements.cc b/src/elements.cc
index 5b454e5964ae2caf873f30adc7ddc83b1f6f08c8..6459279dea56753cbbdfa194678d77c0cb6b11ea 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -30,7 +30,7 @@
 #include "objects.h"
 #include "elements.h"
 #include "utils.h"
-
+#include "v8conversions.h"

 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
 // several abstract ElementsAccessor classes are used to allow sharing
@@ -483,6 +483,63 @@ static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
 }


+static void TraceTopFrame() {
+  StackFrameIterator it;
+  if (it.done()) {
+    PrintF("unknown location (no JavaScript frames present)");
+    return;
+  }
+  StackFrame* raw_frame = it.frame();
+  if (raw_frame->is_internal()) {
+    Isolate* isolate = Isolate::Current();
+    Code* apply_builtin = isolate->builtins()->builtin(
+        Builtins::kFunctionApply);
+    if (raw_frame->unchecked_code() == apply_builtin) {
+      PrintF("apply from ");
+      it.Advance();
+      raw_frame = it.frame();
+    }
+  }
+  JavaScriptFrame::PrintTop(stdout, false, true);
+}
+
+
+void CheckArrayAbuse(JSObject* obj, const char* op, uint32_t key) {
+  Object* raw_length = NULL;
+  const char* elements_type = "array";
+  if (obj->IsJSArray()) {
+    JSArray* array = JSArray::cast(obj);
+    raw_length = array->length();
+  } else {
+    raw_length = Smi::FromInt(obj->elements()->length());
+    elements_type = "object";
+  }
+
+  if (raw_length->IsNumber()) {
+    double n = raw_length->Number();
+    if (FastI2D(FastD2UI(n)) == n) {
+      int32_t int32_length = DoubleToInt32(n);
+      if (key >= static_cast<uint32_t>(int32_length)) {
+        PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
+               elements_type, op, elements_type,
+               static_cast<int>(int32_length),
+               static_cast<int>(key));
+        TraceTopFrame();
+        PrintF("]\n");
+      }
+    } else {
+      PrintF("[%s elements length not integer value in ", elements_type);
+      TraceTopFrame();
+      PrintF("]\n");
+    }
+  } else {
+    PrintF("[%s elements length not a number in ", elements_type);
+    TraceTopFrame();
+    PrintF("]\n");
+  }
+}
+
+
 // Base class for element handler implementations. Contains the
 // the common logic for objects with different ElementsKinds.
 // Subclasses must specialize method for which the element
@@ -570,6 +627,11 @@ class ElementsAccessorBase : public ElementsAccessor {
     if (backing_store == NULL) {
       backing_store = holder->elements();
     }
+
+    if (FLAG_trace_array_abuse) {
+      CheckArrayAbuse(holder, "element read", key);
+    }
+
     return ElementsAccessorSubclass::GetImpl(
         receiver, holder, key, backing_store);
   }
Index: src/elements.h
diff --git a/src/elements.h b/src/elements.h
index e25076ba5c6ed1d527207dbe3a7c6f7b226c37e9..167fb91197b024453e711cf7687f5d5a09e0d48a 100644
--- a/src/elements.h
+++ b/src/elements.h
@@ -197,6 +197,8 @@ class ElementsAccessor {
   DISALLOW_COPY_AND_ASSIGN(ElementsAccessor);
 };

+void CheckArrayAbuse(JSObject* obj, const char* op, uint32_t key);
+
 } }  // namespace v8::internal

 #endif  // V8_ELEMENTS_H_
Index: src/flag-definitions.h
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 4a0d3c661a24cb6ecd292441f53fcb11d16941ee..747e7c1f3c131d041785b876ca5587e86565f7ed 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -363,6 +363,7 @@ DEFINE_bool(cache_prototype_transitions, true, "cache prototype transitions")

 // debug.cc
DEFINE_bool(trace_debug_json, false, "trace debugging JSON request/response")
+DEFINE_bool(trace_array_abuse, false, "trace out-of-bounds array accesses")
 DEFINE_bool(debugger_auto_break, true,
"automatically set the debug break flag when debugger commands are "
             "in the queue")
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 46539311de9625d9c7ffccc54bd476ab5510a47b..b3a5658ca03181502734054f0a640d4a75a854e6 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -10405,6 +10405,11 @@ MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
          HasDictionaryArgumentsElements() ||
          (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
   Isolate* isolate = GetIsolate();
+  if (FLAG_trace_array_abuse) {
+    if (IsExternalArrayElementsKind(GetElementsKind())) {
+      CheckArrayAbuse(this, "external elements write", index);
+    }
+  }
   switch (GetElementsKind()) {
     case FAST_SMI_ELEMENTS:
     case FAST_ELEMENTS:
Index: test/mjsunit/compiler/array-access.js
diff --git a/test/mjsunit/compiler/array-access.js b/test/mjsunit/compiler/array-access.js index 65b3c99b422872d0f24f5cf7b2d67f567d3373f4..cdad595cdf08ae9cca30dcab80fc55a4d792cdb3 100644
--- a/test/mjsunit/compiler/array-access.js
+++ b/test/mjsunit/compiler/array-access.js
@@ -130,3 +130,9 @@ for (var i = 0; i < 1000; i++) {
 }

 RunArrayBoundsCheckTest();
+
+a = new Array();
+a[3];
+
+a = new Float32Array(2);
+a[3] = 5;


--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to