Skip to content

Commit

Permalink
src: fix exception message encoding on Windows
Browse files Browse the repository at this point in the history
The printf family of functions do not properly display UTF8
strings well on Windows. Use the appropriate wide character
API instead if stderr is a tty.

PR-URL: #3288
Fixes: #3284
Reviewed-By: Bert Belder <[email protected]>
  • Loading branch information
mscdex committed Oct 13, 2015
1 parent 0a7076b commit 2d35607
Showing 1 changed file with 45 additions and 13 deletions.
58 changes: 45 additions & 13 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <vector>

#if defined(NODE_HAVE_I18N_SUPPORT)
#include <unicode/uvernum.h>
Expand Down Expand Up @@ -156,6 +157,38 @@ static Isolate* node_isolate = nullptr;
static v8::Platform* default_platform;


static 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);
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);
WriteConsoleW(stderr_handle, wbuf.data(), n, nullptr, nullptr);
#else
vfprintf(stderr, format, ap);
#endif
va_end(ap);
}


static void CheckImmediate(uv_check_t* handle) {
Environment* env = Environment::from_immediate_check_handle(handle);
HandleScope scope(env->isolate());
Expand Down Expand Up @@ -1404,7 +1437,7 @@ void AppendExceptionLine(Environment* env,
return;
env->set_printed_error(true);
uv_tty_reset_mode();
fprintf(stderr, "\n%s", arrow);
PrintErrorString("\n%s", arrow);
}


Expand Down Expand Up @@ -1432,10 +1465,10 @@ static void ReportException(Environment* env,
// range errors have a trace member set to undefined
if (trace.length() > 0 && !trace_value->IsUndefined()) {
if (arrow.IsEmpty() || !arrow->IsString()) {
fprintf(stderr, "%s\n", *trace);
PrintErrorString("%s\n", *trace);
} else {
node::Utf8Value arrow_string(env->isolate(), arrow);
fprintf(stderr, "%s\n%s\n", *arrow_string, *trace);
PrintErrorString("%s\n%s\n", *arrow_string, *trace);
}
} else {
// this really only happens for RangeErrors, since they're the only
Expand All @@ -1456,20 +1489,19 @@ static void ReportException(Environment* env,
name->IsUndefined()) {
// Not an error object. Just print as-is.
node::Utf8Value message(env->isolate(), er);
fprintf(stderr, "%s\n", *message);
PrintErrorString("%s\n", *message);
} else {
node::Utf8Value name_string(env->isolate(), name);
node::Utf8Value message_string(env->isolate(), message);

if (arrow.IsEmpty() || !arrow->IsString()) {
fprintf(stderr, "%s: %s\n", *name_string, *message_string);
PrintErrorString("%s: %s\n", *name_string, *message_string);
} else {
node::Utf8Value arrow_string(env->isolate(), arrow);
fprintf(stderr,
"%s\n%s: %s\n",
*arrow_string,
*name_string,
*message_string);
PrintErrorString("%s\n%s: %s\n",
*arrow_string,
*name_string,
*message_string);
}
}
}
Expand Down Expand Up @@ -2164,9 +2196,9 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {

static void OnFatalError(const char* location, const char* message) {
if (location) {
fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
PrintErrorString("FATAL ERROR: %s %s\n", location, message);
} else {
fprintf(stderr, "FATAL ERROR: %s\n", message);
PrintErrorString("FATAL ERROR: %s\n", message);
}
fflush(stderr);
ABORT();
Expand Down Expand Up @@ -2985,7 +3017,7 @@ static void RawDebug(const FunctionCallbackInfo<Value>& args) {
CHECK(args.Length() == 1 && args[0]->IsString() &&
"must be called with a single string");
node::Utf8Value message(args.GetIsolate(), args[0]);
fprintf(stderr, "%s\n", *message);
PrintErrorString("%s\n", *message);
fflush(stderr);
}

Expand Down

0 comments on commit 2d35607

Please sign in to comment.