Bug 1167423 - patch 1 - Handle return values of FallibleTArray functions in Console API, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 25 May 2015 12:50:15 +0100
changeset 245462 fc7b8402d18bf9b6d12419cfbc3d9a7246fda85c
parent 245461 4e9fbfd11bfb44b927db71602eccecc3375660e0
child 245463 84ea22e04a6272a6291797e8638c258ee18a69dd
push id28806
push userphilringnalda@gmail.com
push dateTue, 26 May 2015 02:10:16 +0000
treeherdermozilla-central@4362d9251296 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1167423
milestone41.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 1167423 - patch 1 - Handle return values of FallibleTArray functions in Console API, r=smaug
dom/base/Console.cpp
dom/base/Console.h
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -169,17 +169,19 @@ public:
   Initialize(JSContext* aCx, Console::MethodName aName,
              const nsAString& aString, const Sequence<JS::Value>& aArguments)
   {
     mGlobal = JS::CurrentGlobalOrNull(aCx);
     mMethodName = aName;
     mMethodString = aString;
 
     for (uint32_t i = 0; i < aArguments.Length(); ++i) {
-      mArguments.AppendElement(aArguments[i]);
+      if (!mArguments.AppendElement(aArguments[i])) {
+        return;
+      }
     }
   }
 
   void
   SetIDs(uint64_t aOuterID, uint64_t aInnerID)
   {
     MOZ_ASSERT(mIDType == eUnknown);
 
@@ -661,17 +663,19 @@ private:
 
     for (uint32_t i = 0; i < length; ++i) {
       JS::Rooted<JS::Value> value(aCx);
 
       if (!JS_GetElement(aCx, argumentsObj, i, &value)) {
         return;
       }
 
-      arguments.AppendElement(value);
+      if (!arguments.AppendElement(value)) {
+        return;
+      }
     }
 
     mConsole->ProfileMethod(aCx, mAction, arguments);
   }
 
   nsString mAction;
   Sequence<JS::Value> mArguments;
 
@@ -821,44 +825,44 @@ METHOD(GroupCollapsed, "groupCollapsed")
 METHOD(GroupEnd, "groupEnd")
 
 void
 Console::Time(JSContext* aCx, const JS::Handle<JS::Value> aTime)
 {
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
-  if (!aTime.isUndefined()) {
-    data.AppendElement(aTime);
+  if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
+    return;
   }
 
   Method(aCx, MethodTime, NS_LITERAL_STRING("time"), data);
 }
 
 void
 Console::TimeEnd(JSContext* aCx, const JS::Handle<JS::Value> aTime)
 {
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
-  if (!aTime.isUndefined()) {
-    data.AppendElement(aTime);
+  if (!aTime.isUndefined() && !data.AppendElement(aTime)) {
+    return;
   }
 
   Method(aCx, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"), data);
 }
 
 void
 Console::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
 {
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
-  if (aData.isString()) {
-    data.AppendElement(aData);
+  if (aData.isString() && !data.AppendElement(aData)) {
+    return;
   }
 
   Method(aCx, MethodTimeStamp, NS_LITERAL_STRING("timeStamp"), data);
 }
 
 void
 Console::Profile(JSContext* aCx, const Sequence<JS::Value>& aData)
 {
@@ -887,17 +891,19 @@ Console::ProfileMethod(JSContext* aCx, c
 
   RootedDictionary<ConsoleProfileEvent> event(aCx);
   event.mAction = aAction;
 
   event.mArguments.Construct();
   Sequence<JS::Value>& sequence = event.mArguments.Value();
 
   for (uint32_t i = 0; i < aData.Length(); ++i) {
-    sequence.AppendElement(aData[i]);
+    if (!sequence.AppendElement(aData[i])) {
+      return;
+    }
   }
 
   JS::Rooted<JS::Value> eventValue(aCx);
   if (!ToJSValue(aCx, event, &eventValue)) {
     return;
   }
 
   JS::Rooted<JSObject*> eventObj(aCx, &eventValue.toObject());
@@ -1288,23 +1294,28 @@ Console::ProcessCallData(ConsoleCallData
     case MethodInfo:
     case MethodWarn:
     case MethodError:
     case MethodException:
     case MethodDebug:
     case MethodAssert:
       event.mArguments.Construct();
       event.mStyles.Construct();
-      ProcessArguments(cx, aData->mArguments, event.mArguments.Value(),
-                       event.mStyles.Value());
+      if (!ProcessArguments(cx, aData->mArguments, event.mArguments.Value(),
+                            event.mStyles.Value())) {
+        return;
+      }
+
       break;
 
     default:
       event.mArguments.Construct();
-      ArgumentsToValueList(aData->mArguments, event.mArguments.Value());
+      if (!ArgumentsToValueList(aData->mArguments, event.mArguments.Value())) {
+        return;
+      }
   }
 
   if (aData->mMethodName == MethodGroup ||
       aData->mMethodName == MethodGroupCollapsed ||
       aData->mMethodName == MethodGroupEnd) {
     ComposeGroupName(cx, aData->mArguments, event.mGroupName);
   }
 
@@ -1413,58 +1424,62 @@ Console::ProcessCallData(ConsoleCallData
   if (NS_FAILED(mStorage->RecordEvent(innerID, outerID, eventValue))) {
     NS_WARNING("Failed to record a console event.");
   }
 }
 
 namespace {
 
 // Helper method for ProcessArguments. Flushes output, if non-empty, to aSequence.
-void
-FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &output)
+bool
+FlushOutput(JSContext* aCx, Sequence<JS::Value>& aSequence, nsString &aOutput)
 {
-  if (!output.IsEmpty()) {
+  if (!aOutput.IsEmpty()) {
     JS::Rooted<JSString*> str(aCx, JS_NewUCStringCopyN(aCx,
-                                                       output.get(),
-                                                       output.Length()));
+                                                       aOutput.get(),
+                                                       aOutput.Length()));
     if (!str) {
-      return;
+      return false;
     }
 
-    aSequence.AppendElement(JS::StringValue(str));
-    output.Truncate();
+    if (!aSequence.AppendElement(JS::StringValue(str))) {
+      return false;
+    }
+
+    aOutput.Truncate();
   }
+
+  return true;
 }
 
 } // anonymous namespace
 
-void
+bool
 Console::ProcessArguments(JSContext* aCx,
                           const nsTArray<JS::Heap<JS::Value>>& aData,
                           Sequence<JS::Value>& aSequence,
                           Sequence<JS::Value>& aStyles)
 {
   if (aData.IsEmpty()) {
-    return;
+    return true;
   }
 
   if (aData.Length() == 1 || !aData[0].isString()) {
-    ArgumentsToValueList(aData, aSequence);
-    return;
+    return ArgumentsToValueList(aData, aSequence);
   }
 
   JS::Rooted<JS::Value> format(aCx, aData[0]);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, format));
   if (!jsString) {
-    return;
+    return false;
   }
 
   nsAutoJSString string;
   if (!string.init(aCx, jsString)) {
-    return;
+    return false;
   }
 
   nsString::const_iterator start, end;
   string.BeginReading(start);
   string.EndReading(end);
 
   nsString output;
   uint32_t index = 1;
@@ -1542,114 +1557,132 @@ Console::ProcessArguments(JSContext* aCx
     char ch = *start;
     tmp.Append(ch);
     ++start;
 
     switch (ch) {
       case 'o':
       case 'O':
       {
-        FlushOutput(aCx, aSequence, output);
+        if (!FlushOutput(aCx, aSequence, output)) {
+          return false;
+        }
 
         JS::Rooted<JS::Value> v(aCx);
         if (index < aData.Length()) {
           v = aData[index++];
         }
 
-        aSequence.AppendElement(v);
+        if (!aSequence.AppendElement(v)) {
+          return false;
+        }
+
         break;
       }
 
       case 'c':
       {
-        FlushOutput(aCx, aSequence, output);
+        if (!FlushOutput(aCx, aSequence, output)) {
+          return false;
+        }
 
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> v(aCx, aData[index++]);
           JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, v));
           if (!jsString) {
-            return;
+            return false;
           }
 
           int32_t diff = aSequence.Length() - aStyles.Length();
           if (diff > 0) {
             for (int32_t i = 0; i < diff; i++) {
-              aStyles.AppendElement(JS::NullValue());
+              if (!aStyles.AppendElement(JS::NullValue())) {
+                return false;
+              }
             }
           }
-          aStyles.AppendElement(JS::StringValue(jsString));
+
+          if (!aStyles.AppendElement(JS::StringValue(jsString))) {
+            return false;
+          }
         }
         break;
       }
 
       case 's':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
           JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
           if (!jsString) {
-            return;
+            return false;
           }
 
           nsAutoJSString v;
           if (!v.init(aCx, jsString)) {
-            return;
+            return false;
           }
 
           output.Append(v);
         }
         break;
 
       case 'd':
       case 'i':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
 
           int32_t v;
           if (!JS::ToInt32(aCx, value, &v)) {
-            return;
+            return false;
           }
 
           nsCString format;
           MakeFormatString(format, integer, mantissa, 'd');
           output.AppendPrintf(format.get(), v);
         }
         break;
 
       case 'f':
         if (index < aData.Length()) {
           JS::Rooted<JS::Value> value(aCx, aData[index++]);
 
           double v;
           if (!JS::ToNumber(aCx, value, &v)) {
-            return;
+            return false;
           }
 
           nsCString format;
           MakeFormatString(format, integer, mantissa, 'f');
           output.AppendPrintf(format.get(), v);
         }
         break;
 
       default:
         output.Append(tmp);
         break;
     }
   }
 
-  FlushOutput(aCx, aSequence, output);
+  if (!FlushOutput(aCx, aSequence, output)) {
+    return false;
+  }
 
   // Discard trailing style element if there is no output to apply it to.
   if (aStyles.Length() > aSequence.Length()) {
     aStyles.TruncateLength(aSequence.Length());
   }
 
   // The rest of the array, if unused by the format string.
   for (; index < aData.Length(); ++index) {
-    aSequence.AppendElement(aData[index]);
+    if (!aSequence.AppendElement(aData[index])) {
+      return false;
+    }
   }
+
+  return true;
 }
 
 void
 Console::MakeFormatString(nsCString& aFormat, int32_t aInteger,
                           int32_t aMantissa, char aCh)
 {
   aFormat.Append('%');
   if (aInteger >= 0) {
@@ -1765,23 +1798,27 @@ Console::StopTimer(JSContext* aCx, const
   JS::Rooted<JS::Value> value(aCx);
   if (!ToJSValue(aCx, timer, &value)) {
     return JS::UndefinedValue();
   }
 
   return value;
 }
 
-void
+bool
 Console::ArgumentsToValueList(const nsTArray<JS::Heap<JS::Value>>& aData,
                               Sequence<JS::Value>& aSequence)
 {
   for (uint32_t i = 0; i < aData.Length(); ++i) {
-    aSequence.AppendElement(aData[i]);
+    if (!aSequence.AppendElement(aData[i])) {
+      return false;
+    }
   }
+
+  return true;
 }
 
 JS::Value
 Console::IncreaseCounter(JSContext* aCx, const ConsoleStackEntry& aFrame,
                           const nsTArray<JS::Heap<JS::Value>>& aArguments)
 {
   ClearException ce(aCx);
 
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -153,17 +153,17 @@ private:
   //   "string: %s, integer: %d, object: %o, double: %d", 's', 1, window, 0.9
   // The output will be:
   //   [ "string: s, integer: 1, object: ", window, ", double: 0.9" ]
   //
   // The aStyles array is populated with the style strings that the function
   // finds based the format string. The index of the styles matches the indexes
   // of elements that need the custom styling from aSequence. For elements with
   // no custom styling the array is padded with null elements.
-  void
+  bool
   ProcessArguments(JSContext* aCx, const nsTArray<JS::Heap<JS::Value>>& aData,
                    Sequence<JS::Value>& aSequence,
                    Sequence<JS::Value>& aStyles);
 
   void
   MakeFormatString(nsCString& aFormat, int32_t aInteger, int32_t aMantissa,
                    char aCh);
 
@@ -177,17 +177,17 @@ private:
   StartTimer(JSContext* aCx, const JS::Value& aName,
              DOMHighResTimeStamp aTimestamp);
 
   JS::Value
   StopTimer(JSContext* aCx, const JS::Value& aName,
             DOMHighResTimeStamp aTimestamp);
 
   // The method populates a Sequence from an array of JS::Value.
-  void
+  bool
   ArgumentsToValueList(const nsTArray<JS::Heap<JS::Value>>& aData,
                        Sequence<JS::Value>& aSequence);
 
   void
   ProfileMethod(JSContext* aCx, const nsAString& aAction,
                 const Sequence<JS::Value>& aData);
 
   JS::Value