Bug 898122 - Properly squelch exceptions in FormatFrame. r=luke
authorBobby Holley <bobbyholley@gmail.com>
Mon, 29 Jul 2013 14:31:30 -0700
changeset 152731 ef5f21a8fba123a98b77816dc76af7b72ad6a5db
parent 152730 3a974ffb8cf9b59b7dc8ad135b469f7c1f59b3db
child 152732 94eeed0da711dec9e201c44c3bd6bd7225bb9669
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs898122
milestone25.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 898122 - Properly squelch exceptions in FormatFrame. r=luke Given that this is a debugging tool, we don't really want to just throw in the towel if we fail to glean all possible information during stack introspection. Clear the exception and note the failure to the stream.
js/src/jsdbgapi.cpp
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -1030,16 +1030,17 @@ FormatValue(JSContext *cx, const Value &
         return "[function]";
     return buf;
 }
 
 static char *
 FormatFrame(JSContext *cx, const NonBuiltinScriptFrameIter &iter, char *buf, int num,
             JSBool showArgs, JSBool showLocals, JSBool showThisProps)
 {
+    JS_ASSERT(!cx->isExceptionPending());
     RootedScript script(cx, iter.script());
     jsbytecode* pc = iter.pc();
 
     RootedObject scopeChain(cx, iter.scopeChain());
     JSAutoCompartment ac(cx, scopeChain);
 
     const char *filename = script->filename();
     unsigned lineno = PCToLineNumber(script, pc);
@@ -1080,60 +1081,77 @@ FormatFrame(JSContext *cx, const NonBuil
 
     // print the function arguments
     if (showArgs && callObj) {
         uint32_t namedArgCount = 0;
         for (uint32_t i = 0; i < callProps->length; i++) {
             JSPropertyDesc* desc = &callProps->array[i];
             JSAutoByteString nameBytes;
             const char *name = NULL;
-            if (JSVAL_IS_STRING(desc->id))
+            bool hasName = JSVAL_IS_STRING(desc->id);
+            if (hasName)
                 name = FormatValue(cx, desc->id, nameBytes);
-
             JSAutoByteString valueBytes;
             const char *value = FormatValue(cx, desc->value, valueBytes);
 
-            buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
-                                    namedArgCount ? ", " : "",
-                                    name ? name :"",
-                                    name ? " = " : "",
-                                    desc->value.isString() ? "\"" : "",
-                                    value ? value : "?unknown?",
-                                    desc->value.isString() ? "\"" : "");
-            if (!buf)
-                return buf;
+            if (value && (name || !hasName)) {
+                buf = JS_sprintf_append(buf, "%s%s%s%s%s%s",
+                                        namedArgCount ? ", " : "",
+                                        name ? name :"",
+                                        name ? " = " : "",
+                                        desc->value.isString() ? "\"" : "",
+                                        value ? value : "?unknown?",
+                                        desc->value.isString() ? "\"" : "");
+                if (!buf)
+                    return buf;
+            } else {
+                buf = JS_sprintf_append(buf, "    <Failed to get named argument while inspecting stack frame>\n");
+                cx->clearPendingException();
+
+            }
             namedArgCount++;
         }
 
         // print any unnamed trailing args (found in 'arguments' object)
         RootedValue val(cx);
         if (JS_GetProperty(cx, callObj, "arguments", &val) && val.isObject()) {
             uint32_t argCount;
             RootedObject argsObj(cx, &val.toObject());
             if (JS_GetProperty(cx, argsObj, "length", &val) &&
                 ToUint32(cx, val, &argCount) &&
                 argCount > namedArgCount)
             {
                 for (uint32_t k = namedArgCount; k < argCount; k++) {
                     char number[8];
                     JS_snprintf(number, 8, "%d", (int) k);
 
-                    if (JS_GetProperty(cx, argsObj, number, &val)) {
-                        JSAutoByteString valueBytes;
-                        const char *value = FormatValue(cx, val, valueBytes);
+                    JSAutoByteString valueBytes;
+                    const char *value = NULL;
+                    if (JS_GetProperty(cx, argsObj, number, &val) &&
+                        (value = FormatValue(cx, val, valueBytes)))
+                    {
                         buf = JS_sprintf_append(buf, "%s%s%s%s",
                                                 k ? ", " : "",
                                                 val.isString() ? "\"" : "",
                                                 value ? value : "?unknown?",
                                                 val.isString() ? "\"" : "");
                         if (!buf)
                             return buf;
+                    } else {
+                        buf = JS_sprintf_append(buf, "    <Failed to get argument while inspecting stack frame>\n");
+                        cx->clearPendingException();
                     }
                 }
+            } else {
+                buf = JS_sprintf_append(buf, "    <Failed to get 'length' while inspecting stack frame>\n");
+                cx->clearPendingException();
             }
+        } else {
+            buf = JS_sprintf_append(buf, "    <Failed to get 'arguments' while inspecting stack frame>\n");
+            cx->clearPendingException();
         }
     }
 
     // print filename and line number
     buf = JS_sprintf_append(buf, "%s [\"%s\":%d]\n",
                             fun ? ")" : "",
                             filename ? filename : "<unknown>",
                             lineno);
@@ -1152,34 +1170,39 @@ FormatFrame(JSContext *cx, const NonBuil
             if (name && value) {
                 buf = JS_sprintf_append(buf, "    %s = %s%s%s\n",
                                         name,
                                         desc->value.isString() ? "\"" : "",
                                         value,
                                         desc->value.isString() ? "\"" : "");
                 if (!buf)
                     return buf;
+            } else {
+                buf = JS_sprintf_append(buf, "    <Failed to get local while inspecting stack frame>\n");
+                cx->clearPendingException();
             }
         }
     }
 
     // print the value of 'this'
     if (showLocals) {
         if (!thisVal.isUndefined()) {
             JSAutoByteString thisValBytes;
             RootedString thisValStr(cx, ToString<CanGC>(cx, thisVal));
-            if (thisValStr) {
-                if (const char *str = thisValBytes.encodeLatin1(cx, thisValStr)) {
-                    buf = JS_sprintf_append(buf, "    this = %s\n", str);
-                    if (!buf)
-                        return buf;
-                }
+            const char *str = NULL;
+            if (thisValStr &&
+                (str = thisValBytes.encodeLatin1(cx, thisValStr)))
+            {
+                buf = JS_sprintf_append(buf, "    this = %s\n", str);
+                if (!buf)
+                    return buf;
+            } else {
+                buf = JS_sprintf_append(buf, "    <failed to get 'this' value>\n");
+                cx->clearPendingException();
             }
-        } else {
-            buf = JS_sprintf_append(buf, "    <failed to get 'this' value>\n");
         }
     }
 
     // print the properties of 'this', if it is an object
     if (showThisProps && thisProps->array) {
         for (uint32_t i = 0; i < thisProps->length; i++) {
             JSPropertyDesc* desc = &thisProps->array[i];
             if (desc->flags & JSPD_ENUMERATE) {
@@ -1190,21 +1213,25 @@ FormatFrame(JSContext *cx, const NonBuil
                 if (name && value) {
                     buf = JS_sprintf_append(buf, "    this.%s = %s%s%s\n",
                                             name,
                                             desc->value.isString() ? "\"" : "",
                                             value,
                                             desc->value.isString() ? "\"" : "");
                     if (!buf)
                         return buf;
+                } else {
+                    buf = JS_sprintf_append(buf, "    <Failed to format values while inspecting stack frame>\n");
+                    cx->clearPendingException();
                 }
             }
         }
     }
 
+    JS_ASSERT(!cx->isExceptionPending());
     return buf;
 }
 
 JS_PUBLIC_API(char *)
 JS::FormatStackDump(JSContext *cx, char *buf,
                       JSBool showArgs, JSBool showLocals,
                       JSBool showThisProps)
 {