@@ -21,10 +21,11 @@ using v8::Local;
21
21
using v8::Maybe;
22
22
using v8::MaybeLocal;
23
23
using v8::Message;
24
- using v8::NewStringType;
25
24
using v8::Number;
26
25
using v8::Object;
27
26
using v8::ScriptOrigin;
27
+ using v8::StackFrame;
28
+ using v8::StackTrace;
28
29
using v8::String;
29
30
using v8::Undefined;
30
31
using v8::Value;
@@ -44,30 +45,20 @@ namespace per_process {
44
45
static Mutex tty_mutex;
45
46
} // namespace per_process
46
47
47
- void AppendExceptionLine (Environment* env,
48
- Local<Value> er,
49
- Local<Message> message,
50
- enum ErrorHandlingMode mode) {
51
- if (message.IsEmpty ()) return ;
48
+ static const int kMaxErrorSourceLength = 1024 ;
52
49
53
- HandleScope scope (env->isolate ());
54
- Local<Object> err_obj;
55
- if (!er.IsEmpty () && er->IsObject ()) {
56
- err_obj = er.As <Object>();
57
- }
50
+ static std::string GetErrorSource (Isolate* isolate,
51
+ Local<Context> context,
52
+ Local<Message> message,
53
+ bool * added_exception_line) {
54
+ MaybeLocal<String> source_line_maybe = message->GetSourceLine (context);
55
+ node::Utf8Value encoded_source (isolate, source_line_maybe.ToLocalChecked ());
56
+ std::string sourceline (*encoded_source, encoded_source.length ());
58
57
59
- // Print (filename):(line number): (message).
60
- ScriptOrigin origin = message->GetScriptOrigin ();
61
- node::Utf8Value filename (env->isolate (), message->GetScriptResourceName ());
62
- const char * filename_string = *filename;
63
- int linenum = message->GetLineNumber (env->context ()).FromJust ();
64
- // Print line of source code.
65
- MaybeLocal<String> source_line_maybe = message->GetSourceLine (env->context ());
66
- node::Utf8Value sourceline (env->isolate (),
67
- source_line_maybe.ToLocalChecked ());
68
- const char * sourceline_string = *sourceline;
69
- if (strstr (sourceline_string, " node-do-not-add-exception-line" ) != nullptr )
70
- return ;
58
+ if (sourceline.find (" node-do-not-add-exception-line" ) != std::string::npos) {
59
+ *added_exception_line = false ;
60
+ return sourceline;
61
+ }
71
62
72
63
// Because of how node modules work, all scripts are wrapped with a
73
64
// "function (module, exports, __filename, ...) {"
@@ -90,53 +81,131 @@ void AppendExceptionLine(Environment* env,
90
81
// sourceline to 78 characters, and we end up not providing very much
91
82
// useful debugging info to the user if we remove 62 characters.
92
83
84
+ // Print (filename):(line number): (message).
85
+ ScriptOrigin origin = message->GetScriptOrigin ();
86
+ node::Utf8Value filename (isolate, message->GetScriptResourceName ());
87
+ const char * filename_string = *filename;
88
+ int linenum = message->GetLineNumber (context).FromJust ();
89
+
93
90
int script_start = (linenum - origin.ResourceLineOffset ()->Value ()) == 1
94
91
? origin.ResourceColumnOffset ()->Value ()
95
92
: 0 ;
96
- int start = message->GetStartColumn (env-> context () ).FromMaybe (0 );
97
- int end = message->GetEndColumn (env-> context () ).FromMaybe (0 );
93
+ int start = message->GetStartColumn (context).FromMaybe (0 );
94
+ int end = message->GetEndColumn (context).FromMaybe (0 );
98
95
if (start >= script_start) {
99
96
CHECK_GE (end, start);
100
97
start -= script_start;
101
98
end -= script_start;
102
99
}
103
100
104
- char arrow[1024 ];
105
- int max_off = sizeof (arrow) - 2 ;
101
+ int max_off = kMaxErrorSourceLength - 2 ;
106
102
107
- int off = snprintf (arrow,
108
- sizeof (arrow),
103
+ char buf[kMaxErrorSourceLength ];
104
+ int off = snprintf (buf,
105
+ kMaxErrorSourceLength ,
109
106
" %s:%i\n %s\n " ,
110
107
filename_string,
111
108
linenum,
112
- sourceline_string );
109
+ sourceline. c_str () );
113
110
CHECK_GE (off, 0 );
114
111
if (off > max_off) {
115
112
off = max_off;
116
113
}
117
114
118
115
// Print wavy underline (GetUnderline is deprecated).
119
116
for (int i = 0 ; i < start; i++) {
120
- if (sourceline_string [i] == ' \0 ' || off >= max_off) {
117
+ if (sourceline [i] == ' \0 ' || off >= max_off) {
121
118
break ;
122
119
}
123
120
CHECK_LT (off, max_off);
124
- arrow [off++] = (sourceline_string [i] == ' \t ' ) ? ' \t ' : ' ' ;
121
+ buf [off++] = (sourceline [i] == ' \t ' ) ? ' \t ' : ' ' ;
125
122
}
126
123
for (int i = start; i < end; i++) {
127
- if (sourceline_string [i] == ' \0 ' || off >= max_off) {
124
+ if (sourceline [i] == ' \0 ' || off >= max_off) {
128
125
break ;
129
126
}
130
127
CHECK_LT (off, max_off);
131
- arrow [off++] = ' ^' ;
128
+ buf [off++] = ' ^' ;
132
129
}
133
130
CHECK_LE (off, max_off);
134
- arrow[off] = ' \n ' ;
135
- arrow[off + 1 ] = ' \0 ' ;
131
+ buf[off] = ' \n ' ;
132
+ buf[off + 1 ] = ' \0 ' ;
133
+
134
+ *added_exception_line = true ;
135
+ return std::string (buf);
136
+ }
137
+
138
+ void PrintStackTrace (Isolate* isolate, Local<StackTrace> stack) {
139
+ for (int i = 0 ; i < stack->GetFrameCount () - 1 ; i++) {
140
+ Local<StackFrame> stack_frame = stack->GetFrame (isolate, i);
141
+ node::Utf8Value fn_name_s (isolate, stack_frame->GetFunctionName ());
142
+ node::Utf8Value script_name (isolate, stack_frame->GetScriptName ());
143
+ const int line_number = stack_frame->GetLineNumber ();
144
+ const int column = stack_frame->GetColumn ();
145
+
146
+ if (stack_frame->IsEval ()) {
147
+ if (stack_frame->GetScriptId () == Message::kNoScriptIdInfo ) {
148
+ fprintf (stderr, " at [eval]:%i:%i\n " , line_number, column);
149
+ } else {
150
+ fprintf (stderr,
151
+ " at [eval] (%s:%i:%i)\n " ,
152
+ *script_name,
153
+ line_number,
154
+ column);
155
+ }
156
+ break ;
157
+ }
158
+
159
+ if (fn_name_s.length () == 0 ) {
160
+ fprintf (stderr, " at %s:%i:%i\n " , *script_name, line_number, column);
161
+ } else {
162
+ fprintf (stderr,
163
+ " at %s (%s:%i:%i)\n " ,
164
+ *fn_name_s,
165
+ *script_name,
166
+ line_number,
167
+ column);
168
+ }
169
+ }
170
+ fflush (stderr);
171
+ }
172
+
173
+ void PrintCaughtException (Isolate* isolate,
174
+ Local<Context> context,
175
+ const v8::TryCatch& try_catch) {
176
+ CHECK (try_catch.HasCaught ());
177
+ Local<Value> err = try_catch.Exception ();
178
+ Local<Message> message = try_catch.Message ();
179
+ Local<v8::StackTrace> stack = message->GetStackTrace ();
180
+ node::Utf8Value reason (isolate,
181
+ err->ToDetailString (context).ToLocalChecked ());
182
+ bool added_exception_line = false ;
183
+ std::string source =
184
+ GetErrorSource (isolate, context, message, &added_exception_line);
185
+ fprintf (stderr, " %s\n " , source.c_str ());
186
+ fprintf (stderr, " %s\n " , *reason);
187
+ PrintStackTrace (isolate, stack);
188
+ }
189
+
190
+ void AppendExceptionLine (Environment* env,
191
+ Local<Value> er,
192
+ Local<Message> message,
193
+ enum ErrorHandlingMode mode) {
194
+ if (message.IsEmpty ()) return ;
195
+
196
+ HandleScope scope (env->isolate ());
197
+ Local<Object> err_obj;
198
+ if (!er.IsEmpty () && er->IsObject ()) {
199
+ err_obj = er.As <Object>();
200
+ }
136
201
137
- Local<String> arrow_str =
138
- String::NewFromUtf8 (env->isolate (), arrow, NewStringType::kNormal )
139
- .ToLocalChecked ();
202
+ bool added_exception_line = false ;
203
+ std::string source = GetErrorSource (
204
+ env->isolate (), env->context (), message, &added_exception_line);
205
+ if (!added_exception_line) {
206
+ return ;
207
+ }
208
+ MaybeLocal<Value> arrow_str = ToV8Value (env->context (), source);
140
209
141
210
const bool can_set_arrow = !arrow_str.IsEmpty () && !err_obj.IsEmpty ();
142
211
// If allocating arrow_str failed, print it out. There's not much else to do.
@@ -150,13 +219,14 @@ void AppendExceptionLine(Environment* env,
150
219
env->set_printed_error (true );
151
220
152
221
uv_tty_reset_mode ();
153
- PrintErrorString (" \n %s" , arrow );
222
+ PrintErrorString (" \n %s" , source. c_str () );
154
223
return ;
155
224
}
156
225
157
226
CHECK (err_obj
158
- ->SetPrivate (
159
- env->context (), env->arrow_message_private_symbol (), arrow_str)
227
+ ->SetPrivate (env->context (),
228
+ env->arrow_message_private_symbol (),
229
+ arrow_str.ToLocalChecked ())
160
230
.FromMaybe (false ));
161
231
}
162
232
0 commit comments