Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fe01d0d

Browse filesBrowse files
mscdexjasnell
authored andcommitted
src: fix exception message encoding on Windows
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 <bertbelder@gmail.com>
1 parent eb7c3fb commit fe01d0d
Copy full SHA for fe01d0d

File tree

Expand file treeCollapse file tree

1 file changed

+45
-13
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+45
-13
lines changed
Open diff view settings
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+45-13Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <stdlib.h>
5252
#include <string.h>
5353
#include <sys/types.h>
54+
#include <vector>
5455

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

158159

160+
static void PrintErrorString(const char* format, ...) {
161+
va_list ap;
162+
va_start(ap, format);
163+
#ifdef _WIN32
164+
HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
165+
166+
// Check if stderr is something other than a tty/console
167+
if (stderr_handle == INVALID_HANDLE_VALUE ||
168+
stderr_handle == nullptr ||
169+
uv_guess_handle(_fileno(stderr)) != UV_TTY) {
170+
vfprintf(stderr, format, ap);
171+
return;
172+
}
173+
174+
// Fill in any placeholders
175+
int n = _vscprintf(format, ap);
176+
std::vector<char> out(n + 1);
177+
vsprintf(out.data(), format, ap);
178+
179+
// Get required wide buffer size
180+
n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0);
181+
182+
std::vector<wchar_t> wbuf(n);
183+
MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n);
184+
WriteConsoleW(stderr_handle, wbuf.data(), n, nullptr, nullptr);
185+
#else
186+
vfprintf(stderr, format, ap);
187+
#endif
188+
va_end(ap);
189+
}
190+
191+
159192
static void CheckImmediate(uv_check_t* handle) {
160193
Environment* env = Environment::from_immediate_check_handle(handle);
161194
HandleScope scope(env->isolate());
@@ -1416,7 +1449,7 @@ void AppendExceptionLine(Environment* env,
14161449
return;
14171450
env->set_printed_error(true);
14181451
uv_tty_reset_mode();
1419-
fprintf(stderr, "\n%s", arrow);
1452+
PrintErrorString("\n%s", arrow);
14201453
}
14211454

14221455

@@ -1444,10 +1477,10 @@ static void ReportException(Environment* env,
14441477
// range errors have a trace member set to undefined
14451478
if (trace.length() > 0 && !trace_value->IsUndefined()) {
14461479
if (arrow.IsEmpty() || !arrow->IsString()) {
1447-
fprintf(stderr, "%s\n", *trace);
1480+
PrintErrorString("%s\n", *trace);
14481481
} else {
14491482
node::Utf8Value arrow_string(env->isolate(), arrow);
1450-
fprintf(stderr, "%s\n%s\n", *arrow_string, *trace);
1483+
PrintErrorString("%s\n%s\n", *arrow_string, *trace);
14511484
}
14521485
} else {
14531486
// this really only happens for RangeErrors, since they're the only
@@ -1468,20 +1501,19 @@ static void ReportException(Environment* env,
14681501
name->IsUndefined()) {
14691502
// Not an error object. Just print as-is.
14701503
node::Utf8Value message(env->isolate(), er);
1471-
fprintf(stderr, "%s\n", *message);
1504+
PrintErrorString("%s\n", *message);
14721505
} else {
14731506
node::Utf8Value name_string(env->isolate(), name);
14741507
node::Utf8Value message_string(env->isolate(), message);
14751508

14761509
if (arrow.IsEmpty() || !arrow->IsString()) {
1477-
fprintf(stderr, "%s: %s\n", *name_string, *message_string);
1510+
PrintErrorString("%s: %s\n", *name_string, *message_string);
14781511
} else {
14791512
node::Utf8Value arrow_string(env->isolate(), arrow);
1480-
fprintf(stderr,
1481-
"%s\n%s: %s\n",
1482-
*arrow_string,
1483-
*name_string,
1484-
*message_string);
1513+
PrintErrorString("%s\n%s: %s\n",
1514+
*arrow_string,
1515+
*name_string,
1516+
*message_string);
14851517
}
14861518
}
14871519
}
@@ -2176,9 +2208,9 @@ void DLOpen(const FunctionCallbackInfo<Value>& args) {
21762208

21772209
static void OnFatalError(const char* location, const char* message) {
21782210
if (location) {
2179-
fprintf(stderr, "FATAL ERROR: %s %s\n", location, message);
2211+
PrintErrorString("FATAL ERROR: %s %s\n", location, message);
21802212
} else {
2181-
fprintf(stderr, "FATAL ERROR: %s\n", message);
2213+
PrintErrorString("FATAL ERROR: %s\n", message);
21822214
}
21832215
fflush(stderr);
21842216
ABORT();
@@ -3002,7 +3034,7 @@ static void RawDebug(const FunctionCallbackInfo<Value>& args) {
30023034
CHECK(args.Length() == 1 && args[0]->IsString() &&
30033035
"must be called with a single string");
30043036
node::Utf8Value message(args.GetIsolate(), args[0]);
3005-
fprintf(stderr, "%s\n", *message);
3037+
PrintErrorString("%s\n", *message);
30063038
fflush(stderr);
30073039
}
30083040

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.