1
1
#include < cerrno>
2
2
#include < cstdarg>
3
+ #include < sstream>
3
4
4
5
#include " debug_utils-inl.h"
5
6
#include " node_errors.h"
@@ -15,6 +16,7 @@ namespace node {
15
16
using errors::TryCatchScope;
16
17
using v8::Boolean ;
17
18
using v8::Context;
19
+ using v8::EscapableHandleScope;
18
20
using v8::Exception;
19
21
using v8::Function;
20
22
using v8::FunctionCallbackInfo;
@@ -185,23 +187,65 @@ static std::string GetErrorSource(Isolate* isolate,
185
187
return buf + std::string (underline_buf, off);
186
188
}
187
189
188
- static std::string FormatStackTrace (Isolate* isolate, Local<StackTrace> stack) {
190
+ static std::atomic<bool > is_in_oom{false };
191
+ static std::atomic<bool > is_retrieving_js_stacktrace{false };
192
+ MaybeLocal<StackTrace> GetCurrentStackTrace (Isolate* isolate, int frame_count) {
193
+ if (isolate == nullptr ) {
194
+ return MaybeLocal<StackTrace>();
195
+ }
196
+ // Generating JavaScript stack trace can result in V8 fatal error,
197
+ // which can re-enter this function.
198
+ if (is_retrieving_js_stacktrace.load ()) {
199
+ return MaybeLocal<StackTrace>();
200
+ }
201
+
202
+ // Can not capture the stacktrace when the isolate is in a OOM state or no
203
+ // context is entered.
204
+ if (is_in_oom.load () || !isolate->InContext ()) {
205
+ return MaybeLocal<StackTrace>();
206
+ }
207
+
208
+ constexpr StackTrace::StackTraceOptions options =
209
+ static_cast <StackTrace::StackTraceOptions>(
210
+ StackTrace::kDetailed |
211
+ StackTrace::kExposeFramesAcrossSecurityOrigins );
212
+
213
+ is_retrieving_js_stacktrace.store (true );
214
+ EscapableHandleScope scope (isolate);
215
+ Local<StackTrace> stack =
216
+ StackTrace::CurrentStackTrace (isolate, frame_count, options);
217
+
218
+ is_retrieving_js_stacktrace.store (false );
219
+ if (stack->GetFrameCount () == 0 ) {
220
+ return MaybeLocal<StackTrace>();
221
+ }
222
+
223
+ return scope.Escape (stack);
224
+ }
225
+
226
+ static std::string FormatStackTrace (
227
+ Isolate* isolate,
228
+ Local<StackTrace> stack,
229
+ StackTracePrefix prefix = StackTracePrefix::kAt ) {
189
230
std::string result;
190
231
for (int i = 0 ; i < stack->GetFrameCount (); i++) {
191
232
Local<StackFrame> stack_frame = stack->GetFrame (isolate, i);
192
233
node::Utf8Value fn_name_s (isolate, stack_frame->GetFunctionName ());
193
234
node::Utf8Value script_name (isolate, stack_frame->GetScriptName ());
194
235
const int line_number = stack_frame->GetLineNumber ();
195
236
const int column = stack_frame->GetColumn ();
196
-
237
+ std::string prefix_str = prefix == StackTracePrefix::kAt
238
+ ? " at "
239
+ : std::to_string (i + 1 ) + " : " ;
197
240
if (stack_frame->IsEval ()) {
198
241
if (stack_frame->GetScriptId () == Message::kNoScriptIdInfo ) {
199
- result += SPrintF (" at [eval]:%i:%i\n " , line_number, column);
242
+ result += SPrintF (" %s [eval]:%i:%i\n " , prefix_str , line_number, column);
200
243
} else {
201
244
std::vector<char > buf (script_name.length () + 64 );
202
245
snprintf (buf.data (),
203
246
buf.size (),
204
- " at [eval] (%s:%i:%i)\n " ,
247
+ " %s[eval] (%s:%i:%i)\n " ,
248
+ prefix_str.c_str (),
205
249
*script_name,
206
250
line_number,
207
251
column);
@@ -214,7 +258,8 @@ static std::string FormatStackTrace(Isolate* isolate, Local<StackTrace> stack) {
214
258
std::vector<char > buf (script_name.length () + 64 );
215
259
snprintf (buf.data (),
216
260
buf.size (),
217
- " at %s:%i:%i\n " ,
261
+ " %s%s:%i:%i\n " ,
262
+ prefix_str.c_str (),
218
263
*script_name,
219
264
line_number,
220
265
column);
@@ -223,7 +268,8 @@ static std::string FormatStackTrace(Isolate* isolate, Local<StackTrace> stack) {
223
268
std::vector<char > buf (fn_name_s.length () + script_name.length () + 64 );
224
269
snprintf (buf.data (),
225
270
buf.size (),
226
- " at %s (%s:%i:%i)\n " ,
271
+ " %s%s (%s:%i:%i)\n " ,
272
+ prefix_str.c_str (),
227
273
*fn_name_s,
228
274
*script_name,
229
275
line_number,
@@ -239,8 +285,10 @@ static void PrintToStderrAndFlush(const std::string& str) {
239
285
fflush (stderr);
240
286
}
241
287
242
- void PrintStackTrace (Isolate* isolate, Local<StackTrace> stack) {
243
- PrintToStderrAndFlush (FormatStackTrace (isolate, stack));
288
+ void PrintStackTrace (Isolate* isolate,
289
+ Local<StackTrace> stack,
290
+ StackTracePrefix prefix) {
291
+ PrintToStderrAndFlush (FormatStackTrace (isolate, stack, prefix));
244
292
}
245
293
246
294
std::string FormatCaughtException (Isolate* isolate,
@@ -329,7 +377,8 @@ void AppendExceptionLine(Environment* env,
329
377
}
330
378
331
379
[[noreturn]] void Abort () {
332
- DumpBacktrace (stderr);
380
+ DumpNativeBacktrace (stderr);
381
+ DumpJavaScriptBacktrace (stderr);
333
382
fflush (stderr);
334
383
ABORT_NO_BACKTRACE ();
335
384
}
@@ -338,14 +387,15 @@ void AppendExceptionLine(Environment* env,
338
387
std::string name = GetHumanReadableProcessName ();
339
388
340
389
fprintf (stderr,
341
- " %s: %s:%s%s Assertion `%s' failed.\n " ,
390
+ " \n "
391
+ " # %s: %s at %s\n "
392
+ " # Assertion failed: %s\n\n " ,
342
393
name.c_str (),
343
- info.file_line ,
344
- info.function ,
345
- *info.function ? " :" : " " ,
394
+ info.function ? info.function : " (unknown function)" ,
395
+ info.file_line ? info.file_line : " (unknown source location)" ,
346
396
info.message );
347
- fflush (stderr);
348
397
398
+ fflush (stderr);
349
399
Abort ();
350
400
}
351
401
@@ -528,6 +578,9 @@ static void ReportFatalException(Environment* env,
528
578
529
579
[[noreturn]] void OOMErrorHandler (const char * location,
530
580
const v8::OOMDetails& details) {
581
+ // We should never recover from this handler so once it's true it's always
582
+ // true.
583
+ is_in_oom.store (true );
531
584
const char * message =
532
585
details.is_heap_oom ? " Allocation failed - JavaScript heap out of memory"
533
586
: " Allocation failed - process out of memory" ;
0 commit comments