You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2020/04/16 20:20:16 UTC

[couchdb] 05/07: Report error messages at global scope

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch fix-couchjs-utf8-conversions-take2
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 0b6a9cc4f7b71899927765e21d986dd4d3457d7a
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu Apr 16 14:11:30 2020 -0500

    Report error messages at global scope
    
    Previously we weren't reporting any uncaught exceptions or compilation
    errors. This changes that to print any compilation errors or any
    uncaught exceptions with stack traces.
    
    The previous implementation of `couch_error` was attempting to call
    `String.replace` on the `stack` member string of the thrown exception.
    This likely never worked and attempting to fix I was unable to properly
    invoke the `String.replace` function. This changes the implementation to
    use the builtin stack formatting method instead.
---
 src/couch/priv/couch_js/60/main.cpp |  20 ++++++-
 src/couch/priv/couch_js/60/util.cpp | 107 +++++++++++++++++++++---------------
 2 files changed, 82 insertions(+), 45 deletions(-)

diff --git a/src/couch/priv/couch_js/60/main.cpp b/src/couch/priv/couch_js/60/main.cpp
index 11f8152..f0a4e31 100644
--- a/src/couch/priv/couch_js/60/main.cpp
+++ b/src/couch/priv/couch_js/60/main.cpp
@@ -21,6 +21,8 @@
 #include <unistd.h>
 #endif
 
+#include <sstream>
+
 #include <jsapi.h>
 #include <js/Initialization.h>
 #include <js/Conversions.h>
@@ -489,7 +491,14 @@ main(int argc, const char* argv[])
         JS::RootedScript script(cx);
 
         if(!JS_CompileScript(cx, scriptsrc, slen, options, &script)) {
-            fprintf(stderr, "Failed to compile script.\n");
+            JS::RootedValue exc(cx);
+            if(!JS_GetPendingException(cx, &exc)) {
+                fprintf(stderr, "Failed to compile script.\n");
+            } else {
+                JS::RootedObject exc_obj(cx, &exc.toObject());
+                JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+                couch_error(cx, report);
+            }
             return 1;
         }
 
@@ -497,7 +506,14 @@ main(int argc, const char* argv[])
 
         JS::RootedValue result(cx);
         if(JS_ExecuteScript(cx, script, &result) != true) {
-            fprintf(stderr, "Failed to execute script.\n");
+            JS::RootedValue exc(cx);
+            if(!JS_GetPendingException(cx, &exc)) {
+                fprintf(stderr, "Failed to execute script.\n");
+            } else {
+                JS::RootedObject exc_obj(cx, &exc.toObject());
+                JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+                couch_error(cx, report);
+            }
             return 1;
         }
 
diff --git a/src/couch/priv/couch_js/60/util.cpp b/src/couch/priv/couch_js/60/util.cpp
index 9ea9af8..cafb01b 100644
--- a/src/couch/priv/couch_js/60/util.cpp
+++ b/src/couch/priv/couch_js/60/util.cpp
@@ -13,6 +13,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <sstream>
+
 #include <jsapi.h>
 #include <js/Initialization.h>
 #include <js/CharacterEncoding.h>
@@ -274,51 +276,70 @@ couch_print(JSContext* cx, JS::HandleValue obj, bool use_stderr)
 void
 couch_error(JSContext* cx, JSErrorReport* report)
 {
-    JS::RootedValue v(cx), stack(cx), replace(cx);
-    char* bytes;
-    JSObject* regexp;
-
-    if(!report || !JSREPORT_IS_WARNING(report->flags))
-    {
-        fprintf(stderr, "%s\n", report->message().c_str());
-
-        // Print a stack trace, if available.
-        if (JSREPORT_IS_EXCEPTION(report->flags) &&
-            JS_GetPendingException(cx, &v))
-        {
-            // Clear the exception before an JS method calls or the result is
-            // infinite, recursive error report generation.
-            JS_ClearPendingException(cx);
-
-            // Use JS regexp to indent the stack trace.
-            // If the regexp can't be created, don't JS_ReportErrorUTF8 since it is
-            // probably not productive to wind up here again.
-            JS::RootedObject vobj(cx, v.toObjectOrNull());
-
-            if(JS_GetProperty(cx, vobj, "stack", &stack) &&
-               (regexp = JS_NewRegExpObject(
-                   cx, "^(?=.)", 6, JSREG_GLOB | JSREG_MULTILINE)))
-            {
-                // Set up the arguments to ``String.replace()``
-                JS::AutoValueVector re_args(cx);
-                JS::RootedValue arg0(cx, JS::ObjectValue(*regexp));
-                auto arg1 = JS::StringValue(string_to_js(cx, "\t"));
-
-                if (re_args.append(arg0) && re_args.append(arg1)) {
-                    // Perform the replacement
-                    JS::RootedObject sobj(cx, stack.toObjectOrNull());
-                    if(JS_GetProperty(cx, sobj, "replace", &replace) &&
-                       JS_CallFunctionValue(cx, sobj, replace, re_args, &v))
-                    {
-                        // Print the result
-                        bytes = enc_string(cx, v, NULL);
-                        fprintf(stderr, "Stacktrace:\n%s", bytes);
-                        JS_free(cx, bytes);
-                    }
-                }
-            }
+    if(!report) {
+        return;
+    }
+
+    std::ostringstream msg;
+
+    if(JSREPORT_IS_WARNING(report->flags)) {
+        if(JSREPORT_IS_STRICT(report->flags)) {
+            msg << "strict warning";
+        } else {
+            msg << "warning";
+        }
+    } else {
+        msg << "error";
+    }
+
+    msg << ": " << report->message().c_str();
+
+    mozilla::Maybe<JSAutoCompartment> ac;
+    JS::RootedValue exc(cx);
+    JS::RootedObject exc_obj(cx);
+    JS::RootedObject stack_obj(cx);
+    JS::RootedString stack_str(cx);
+    JS::RootedValue stack_val(cx);
+
+    if(!JS_GetPendingException(cx, &exc)) {
+        goto done;
+    }
+
+    // Clear the exception before an JS method calls or the result is
+    // infinite, recursive error report generation.
+    JS_ClearPendingException(cx);
+
+    exc_obj.set(exc.toObjectOrNull());
+    stack_obj.set(JS::ExceptionStackOrNull(exc_obj));
+
+    if(!stack_obj) {
+        // Compilation errors don't have a stack
+
+        msg << " at ";
+
+        if(report->filename) {
+            msg << report->filename;
+        } else {
+            msg << "<unknown>";
         }
+
+        if(report->lineno) {
+            msg << ':' << report->lineno << ':' << report->column;
+        }
+
+        goto done;
+    }
+
+    if(!JS::BuildStackString(cx, stack_obj, &stack_str, 2)) {
+        goto done;
     }
+
+    stack_val.set(JS::StringValue(stack_str));
+    msg << std::endl << std::endl << js_to_string(cx, stack_val).c_str();
+
+done:
+    msg << std::endl;
+    fprintf(stderr, "%s", msg.str().c_str());
 }