diff options
author | Anna Henningsen <anna@addaleax.net> | 2020-01-21 22:30:35 +0300 |
---|---|---|
committer | Anna Henningsen <anna@addaleax.net> | 2020-01-24 00:39:00 +0300 |
commit | 32e7e813e93ec3d0625d315658288769e448dd99 (patch) | |
tree | 9479d9ed447e6a75b158a43a558e3aadb2b1db63 /src/node_errors.cc | |
parent | 9cc747bfcea131797fbf0fcc805f1d7fa244b7da (diff) |
src: use custom fprintf alike to write errors to stderr
This allows printing errors that contain nul characters, for example.
Fixes: https://github.com/nodejs/node/issues/28761
Fixes: https://github.com/nodejs/node/issues/31218
PR-URL: https://github.com/nodejs/node/pull/31446
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Diffstat (limited to 'src/node_errors.cc')
-rw-r--r-- | src/node_errors.cc | 127 |
1 files changed, 40 insertions, 87 deletions
diff --git a/src/node_errors.cc b/src/node_errors.cc index 7e23fca28df..f82054c339b 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -1,6 +1,7 @@ #include <cerrno> #include <cstdarg> +#include "debug_utils-inl.h" #include "node_errors.h" #include "node_internals.h" #ifdef NODE_REPORT @@ -10,10 +11,6 @@ #include "node_v8_platform-inl.h" #include "util-inl.h" -#ifdef __ANDROID__ -#include <android/log.h> -#endif - namespace node { using errors::TryCatchScope; @@ -54,8 +51,6 @@ namespace per_process { static Mutex tty_mutex; } // namespace per_process -static const int kMaxErrorSourceLength = 1024; - static std::string GetErrorSource(Isolate* isolate, Local<Context> context, Local<Message> message, @@ -107,41 +102,35 @@ static std::string GetErrorSource(Isolate* isolate, end -= script_start; } - int max_off = kMaxErrorSourceLength - 2; - - char buf[kMaxErrorSourceLength]; - int off = snprintf(buf, - kMaxErrorSourceLength, - "%s:%i\n%s\n", - filename_string, - linenum, - sourceline.c_str()); - CHECK_GE(off, 0); - if (off > max_off) { - off = max_off; - } + std::string buf = SPrintF("%s:%i\n%s\n", + filename_string, + linenum, + sourceline.c_str()); + CHECK_GT(buf.size(), 0); + constexpr int kUnderlineBufsize = 1020; + char underline_buf[kUnderlineBufsize + 4]; + int off = 0; // Print wavy underline (GetUnderline is deprecated). for (int i = 0; i < start; i++) { - if (sourceline[i] == '\0' || off >= max_off) { + if (sourceline[i] == '\0' || off >= kUnderlineBufsize) { break; } - CHECK_LT(off, max_off); - buf[off++] = (sourceline[i] == '\t') ? '\t' : ' '; + CHECK_LT(off, kUnderlineBufsize); + underline_buf[off++] = (sourceline[i] == '\t') ? '\t' : ' '; } for (int i = start; i < end; i++) { - if (sourceline[i] == '\0' || off >= max_off) { + if (sourceline[i] == '\0' || off >= kUnderlineBufsize) { break; } - CHECK_LT(off, max_off); - buf[off++] = '^'; + CHECK_LT(off, kUnderlineBufsize); + underline_buf[off++] = '^'; } - CHECK_LE(off, max_off); - buf[off] = '\n'; - buf[off + 1] = '\0'; + CHECK_LE(off, kUnderlineBufsize); + underline_buf[off++] = '\n'; *added_exception_line = true; - return std::string(buf); + return buf + std::string(underline_buf, off); } void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) { @@ -154,9 +143,9 @@ void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) { if (stack_frame->IsEval()) { if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) { - fprintf(stderr, " at [eval]:%i:%i\n", line_number, column); + FPrintF(stderr, " at [eval]:%i:%i\n", line_number, column); } else { - fprintf(stderr, + FPrintF(stderr, " at [eval] (%s:%i:%i)\n", *script_name, line_number, @@ -166,12 +155,12 @@ void PrintStackTrace(Isolate* isolate, Local<StackTrace> stack) { } if (fn_name_s.length() == 0) { - fprintf(stderr, " at %s:%i:%i\n", *script_name, line_number, column); + FPrintF(stderr, " at %s:%i:%i\n", script_name, line_number, column); } else { - fprintf(stderr, + FPrintF(stderr, " at %s (%s:%i:%i)\n", - *fn_name_s, - *script_name, + fn_name_s, + script_name, line_number, column); } @@ -189,8 +178,8 @@ void PrintException(Isolate* isolate, bool added_exception_line = false; std::string source = GetErrorSource(isolate, context, message, &added_exception_line); - fprintf(stderr, "%s\n", source.c_str()); - fprintf(stderr, "%s\n", *reason); + FPrintF(stderr, "%s\n", source); + FPrintF(stderr, "%s\n", reason); Local<v8::StackTrace> stack = message->GetStackTrace(); if (!stack.IsEmpty()) PrintStackTrace(isolate, stack); @@ -235,7 +224,7 @@ void AppendExceptionLine(Environment* env, env->set_printed_error(true); ResetStdio(); - PrintErrorString("\n%s", source.c_str()); + FPrintF(stderr, "\n%s", source); return; } @@ -350,10 +339,10 @@ static void ReportFatalException(Environment* env, // range errors have a trace member set to undefined if (trace.length() > 0 && !stack_trace->IsUndefined()) { if (arrow.IsEmpty() || !arrow->IsString() || decorated) { - PrintErrorString("%s\n", *trace); + FPrintF(stderr, "%s\n", trace); } else { node::Utf8Value arrow_string(env->isolate(), arrow); - PrintErrorString("%s\n%s\n", *arrow_string, *trace); + FPrintF(stderr, "%s\n%s\n", arrow_string, trace); } } else { // this really only happens for RangeErrors, since they're the only @@ -371,33 +360,33 @@ static void ReportFatalException(Environment* env, if (message.IsEmpty() || message.ToLocalChecked()->IsUndefined() || name.IsEmpty() || name.ToLocalChecked()->IsUndefined()) { // Not an error object. Just print as-is. - String::Utf8Value message(env->isolate(), error); + node::Utf8Value message(env->isolate(), error); - PrintErrorString("%s\n", - *message ? *message : "<toString() threw exception>"); + FPrintF(stderr, "%s\n", + *message ? message.ToString() : "<toString() threw exception>"); } else { node::Utf8Value name_string(env->isolate(), name.ToLocalChecked()); node::Utf8Value message_string(env->isolate(), message.ToLocalChecked()); if (arrow.IsEmpty() || !arrow->IsString() || decorated) { - PrintErrorString("%s: %s\n", *name_string, *message_string); + FPrintF(stderr, "%s: %s\n", name_string, message_string); } else { node::Utf8Value arrow_string(env->isolate(), arrow); - PrintErrorString( - "%s\n%s: %s\n", *arrow_string, *name_string, *message_string); + FPrintF(stderr, + "%s\n%s: %s\n", arrow_string, name_string, message_string); } } if (!env->options()->trace_uncaught) { - PrintErrorString("(Use `node --trace-uncaught ...` to show " - "where the exception was thrown)\n"); + FPrintF(stderr, "(Use `node --trace-uncaught ...` to show " + "where the exception was thrown)\n"); } } if (env->options()->trace_uncaught) { Local<StackTrace> trace = message->GetStackTrace(); if (!trace.IsEmpty()) { - PrintErrorString("Thrown at:\n"); + FPrintF(stderr, "Thrown at:\n"); PrintStackTrace(env->isolate(), trace); } } @@ -405,42 +394,6 @@ static void ReportFatalException(Environment* env, fflush(stderr); } -void PrintErrorString(const char* format, ...) { - va_list ap; - va_start(ap, format); -#ifdef _WIN32 - HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); - - // Check if stderr is something other than a tty/console - if (stderr_handle == INVALID_HANDLE_VALUE || stderr_handle == nullptr || - uv_guess_handle(_fileno(stderr)) != UV_TTY) { - vfprintf(stderr, format, ap); - va_end(ap); - return; - } - - // Fill in any placeholders - int n = _vscprintf(format, ap); - std::vector<char> out(n + 1); - vsprintf(out.data(), format, ap); - - // Get required wide buffer size - n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0); - - std::vector<wchar_t> wbuf(n); - MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n); - - // Don't include the null character in the output - CHECK_GT(n, 0); - WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr); -#elif defined(__ANDROID__) - __android_log_vprint(ANDROID_LOG_ERROR, "nodejs", format, ap); -#else - vfprintf(stderr, format, ap); -#endif - va_end(ap); -} - [[noreturn]] void FatalError(const char* location, const char* message) { OnFatalError(location, message); // to suppress compiler warning @@ -449,9 +402,9 @@ void PrintErrorString(const char* format, ...) { void OnFatalError(const char* location, const char* message) { if (location) { - PrintErrorString("FATAL ERROR: %s %s\n", location, message); + FPrintF(stderr, "FATAL ERROR: %s %s\n", location, message); } else { - PrintErrorString("FATAL ERROR: %s\n", message); + FPrintF(stderr, "FATAL ERROR: %s\n", message); } #ifdef NODE_REPORT Isolate* isolate = Isolate::GetCurrent(); |