Bug 1260725 - Handle and report OOM in census breakdown parsing; r=jorendorff a=kwierso
authorNick Fitzgerald <fitzgen@gmail.com>
Thu, 31 Mar 2016 14:28:10 -0700
changeset 291110 7614fc1c6285d44b94388f45e7dafb79d8314d89
parent 291109 6e65cda2a0ebba641fc0a6a03a75265f6ee37ea7
child 291111 e1ed27db762457e2263c91d1bc050b8adc240894
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff, kwierso
bugs1260725
milestone48.0a1
Bug 1260725 - Handle and report OOM in census breakdown parsing; r=jorendorff a=kwierso This commit adds OOM checks that were missing to `GetDefaultBreakdown`. Additionally, it replaces uses of `js_new<T>` with `cx->new_<T>` so that OOMs are automatically reported on the context. MozReview-Commit-ID: KUqWdjSBLKn
js/src/jit-test/tests/debug/bug-1260725.js
js/src/vm/UbiNodeCensus.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug-1260725.js
@@ -0,0 +1,12 @@
+// |jit-test| error: out of memory
+
+if (!('oomTest' in this))
+  throw new Error("out of memory");
+
+var dbg = new Debugger;
+dbg.onNewGlobalObject = function(global) {
+  dbg.memory.takeCensus({});
+};
+oomTest(function() {
+  newGlobal({})
+});
--- a/js/src/vm/UbiNodeCensus.cpp
+++ b/js/src/vm/UbiNodeCensus.cpp
@@ -962,17 +962,17 @@ ParseChildBreakdown(JSContext* cx, Handl
     return ParseBreakdown(cx, v);
 }
 
 CountTypePtr
 ParseBreakdown(JSContext* cx, HandleValue breakdownValue)
 {
     if (breakdownValue.isUndefined()) {
         // Construct the default type, { by: 'count' }
-        CountTypePtr simple(js_new<SimpleCount>());
+        CountTypePtr simple(cx->new_<SimpleCount>());
         return simple;
     }
 
     RootedObject breakdown(cx, ToObject(cx, breakdownValue));
     if (!breakdown)
         return nullptr;
 
     RootedValue byValue(cx);
@@ -1020,86 +1020,86 @@ ParseBreakdown(JSContext* cx, HandleValu
             // Since flat strings are null-terminated, and AutoStableStringChars
             // null- terminates if it needs to make a copy, we know that
             // chars.twoByteChars() is null-terminated.
             labelUnique = DuplicateString(cx, chars.twoByteChars());
             if (!labelUnique)
                 return nullptr;
         }
 
-        CountTypePtr simple(js_new<SimpleCount>(labelUnique,
-                                                ToBoolean(countValue),
-                                                ToBoolean(bytesValue)));
+        CountTypePtr simple(cx->new_<SimpleCount>(labelUnique,
+                                                  ToBoolean(countValue),
+                                                  ToBoolean(bytesValue)));
         return simple;
     }
 
     if (StringEqualsAscii(by, "bucket"))
-        return CountTypePtr(js_new<BucketCount>());
+        return CountTypePtr(cx->new_<BucketCount>());
 
     if (StringEqualsAscii(by, "objectClass")) {
         CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
         if (!thenType)
             return nullptr;
 
         CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
         if (!otherType)
             return nullptr;
 
-        return CountTypePtr(js_new<ByObjectClass>(thenType, otherType));
+        return CountTypePtr(cx->new_<ByObjectClass>(thenType, otherType));
     }
 
     if (StringEqualsAscii(by, "coarseType")) {
         CountTypePtr objectsType(ParseChildBreakdown(cx, breakdown, cx->names().objects));
         if (!objectsType)
             return nullptr;
         CountTypePtr scriptsType(ParseChildBreakdown(cx, breakdown, cx->names().scripts));
         if (!scriptsType)
             return nullptr;
         CountTypePtr stringsType(ParseChildBreakdown(cx, breakdown, cx->names().strings));
         if (!stringsType)
             return nullptr;
         CountTypePtr otherType(ParseChildBreakdown(cx, breakdown, cx->names().other));
         if (!otherType)
             return nullptr;
 
-        return CountTypePtr(js_new<ByCoarseType>(objectsType,
-                                                 scriptsType,
-                                                 stringsType,
-                                                 otherType));
+        return CountTypePtr(cx->new_<ByCoarseType>(objectsType,
+                                                   scriptsType,
+                                                   stringsType,
+                                                   otherType));
     }
 
     if (StringEqualsAscii(by, "internalType")) {
         CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
         if (!thenType)
             return nullptr;
 
-        return CountTypePtr(js_new<ByUbinodeType>(thenType));
+        return CountTypePtr(cx->new_<ByUbinodeType>(thenType));
     }
 
     if (StringEqualsAscii(by, "allocationStack")) {
         CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
         if (!thenType)
             return nullptr;
         CountTypePtr noStackType(ParseChildBreakdown(cx, breakdown, cx->names().noStack));
         if (!noStackType)
             return nullptr;
 
-        return CountTypePtr(js_new<ByAllocationStack>(thenType, noStackType));
+        return CountTypePtr(cx->new_<ByAllocationStack>(thenType, noStackType));
     }
 
     if (StringEqualsAscii(by, "filename")) {
         CountTypePtr thenType(ParseChildBreakdown(cx, breakdown, cx->names().then));
         if (!thenType)
             return nullptr;
 
         CountTypePtr noFilenameType(ParseChildBreakdown(cx, breakdown, cx->names().noFilename));
         if (!noFilenameType)
             return nullptr;
 
-        return CountTypePtr(js_new<ByFilename>(Move(thenType), Move(noFilenameType)));
+        return CountTypePtr(cx->new_<ByFilename>(Move(thenType), Move(noFilenameType)));
     }
 
     // We didn't recognize the breakdown type; complain.
     RootedString bySource(cx, ValueToSource(cx, byValue));
     if (!bySource)
         return nullptr;
 
     JSAutoByteString byBytes(cx, bySource);
@@ -1113,41 +1113,59 @@ ParseBreakdown(JSContext* cx, HandleValu
 
 // Get the default census breakdown:
 //
 // { by: "coarseType",
 //   objects: { by: "objectClass" },
 //   other:   { by: "internalType" }
 // }
 static CountTypePtr
-GetDefaultBreakdown()
+GetDefaultBreakdown(JSContext* cx)
 {
-    CountTypePtr byClass(js_new<SimpleCount>());
-    CountTypePtr byClassElse(js_new<SimpleCount>());
-    CountTypePtr objects(js_new<ByObjectClass>(byClass, byClassElse));
+    CountTypePtr byClass(cx->new_<SimpleCount>());
+    if (!byClass)
+        return nullptr;
+
+    CountTypePtr byClassElse(cx->new_<SimpleCount>());
+    if (!byClassElse)
+        return nullptr;
+
+    CountTypePtr objects(cx->new_<ByObjectClass>(byClass, byClassElse));
+    if (!objects)
+        return nullptr;
 
-    CountTypePtr scripts(js_new<SimpleCount>());
-    CountTypePtr strings(js_new<SimpleCount>());
+    CountTypePtr scripts(cx->new_<SimpleCount>());
+    if (!scripts)
+        return nullptr;
+
+    CountTypePtr strings(cx->new_<SimpleCount>());
+    if (!strings)
+        return nullptr;
 
-    CountTypePtr byType(js_new<SimpleCount>());
-    CountTypePtr other(js_new<ByUbinodeType>(byType));
+    CountTypePtr byType(cx->new_<SimpleCount>());
+    if (!byType)
+        return nullptr;
 
-    return CountTypePtr(js_new<ByCoarseType>(objects,
-                                             scripts,
-                                             strings,
-                                             other));
+    CountTypePtr other(cx->new_<ByUbinodeType>(byType));
+    if (!other)
+        return nullptr;
+
+    return CountTypePtr(cx->new_<ByCoarseType>(objects,
+                                               scripts,
+                                               strings,
+                                               other));
 }
 
 bool
 ParseCensusOptions(JSContext* cx, Census& census, HandleObject options, CountTypePtr& outResult)
 {
     RootedValue breakdown(cx, UndefinedValue());
     if (options && !GetProperty(cx, options, options, cx->names().breakdown, &breakdown))
         return false;
 
     outResult = breakdown.isUndefined()
-        ? GetDefaultBreakdown()
+        ? GetDefaultBreakdown(cx)
         : ParseBreakdown(cx, breakdown);
     return !!outResult;
 }
 
 } // namespace ubi
 } // namespace JS