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 <[email protected]> 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()); }
