11#include  < cerrno> 
22#include  < cstdarg> 
3+ #include  < sstream> 
34
45#include  " debug_utils-inl.h" 
56#include  " node_errors.h" 
@@ -15,6 +16,7 @@ namespace node {
1516using  errors::TryCatchScope;
1617using  v8::Boolean;
1718using  v8::Context;
19+ using  v8::EscapableHandleScope;
1820using  v8::Exception;
1921using  v8::Function;
2022using  v8::FunctionCallbackInfo;
@@ -185,23 +187,65 @@ static std::string GetErrorSource(Isolate* isolate,
185187  return  buf + std::string (underline_buf, off);
186188}
187189
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 ) {
189230  std::string result;
190231  for  (int  i = 0 ; i < stack->GetFrameCount (); i++) {
191232    Local<StackFrame> stack_frame = stack->GetFrame (isolate, i);
192233    node::Utf8Value fn_name_s (isolate, stack_frame->GetFunctionName ());
193234    node::Utf8Value script_name (isolate, stack_frame->GetScriptName ());
194235    const  int  line_number = stack_frame->GetLineNumber ();
195236    const  int  column = stack_frame->GetColumn ();
196- 
237+     std::string prefix_str = prefix == StackTracePrefix::kAt 
238+                                  ? "     at " 
239+                                  : std::to_string (i + 1 ) + " : " 
197240    if  (stack_frame->IsEval ()) {
198241      if  (stack_frame->GetScriptId () == Message::kNoScriptIdInfo ) {
199-         result += SPrintF ("     at  [eval]:%i:%i\n " 
242+         result += SPrintF (" %s [eval]:%i:%i\n " , prefix_str , line_number, column);
200243      } else  {
201244        std::vector<char > buf (script_name.length () + 64 );
202245        snprintf (buf.data (),
203246                 buf.size (),
204-                  "     at [eval] (%s:%i:%i)\n " 
247+                  " %s[eval] (%s:%i:%i)\n " 
248+                  prefix_str.c_str (),
205249                 *script_name,
206250                 line_number,
207251                 column);
@@ -214,7 +258,8 @@ static std::string FormatStackTrace(Isolate* isolate, Local<StackTrace> stack) {
214258      std::vector<char > buf (script_name.length () + 64 );
215259      snprintf (buf.data (),
216260               buf.size (),
217-                "     at %s:%i:%i\n " 
261+                " %s%s:%i:%i\n " 
262+                prefix_str.c_str (),
218263               *script_name,
219264               line_number,
220265               column);
@@ -223,7 +268,8 @@ static std::string FormatStackTrace(Isolate* isolate, Local<StackTrace> stack) {
223268      std::vector<char > buf (fn_name_s.length () + script_name.length () + 64 );
224269      snprintf (buf.data (),
225270               buf.size (),
226-                "     at %s (%s:%i:%i)\n " 
271+                " %s%s (%s:%i:%i)\n " 
272+                prefix_str.c_str (),
227273               *fn_name_s,
228274               *script_name,
229275               line_number,
@@ -239,8 +285,10 @@ static void PrintToStderrAndFlush(const std::string& str) {
239285  fflush (stderr);
240286}
241287
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));
244292}
245293
246294std::string FormatCaughtException (Isolate* isolate,
@@ -329,7 +377,8 @@ void AppendExceptionLine(Environment* env,
329377}
330378
331379[[noreturn]] void  Abort () {
332-   DumpBacktrace (stderr);
380+   DumpNativeBacktrace (stderr);
381+   DumpJavaScriptBacktrace (stderr);
333382  fflush (stderr);
334383  ABORT_NO_BACKTRACE ();
335384}
@@ -338,14 +387,15 @@ void AppendExceptionLine(Environment* env,
338387  std::string name = GetHumanReadableProcessName ();
339388
340389  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 " 
342393          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)" 
346396          info.message );
347-   fflush (stderr);
348397
398+   fflush (stderr);
349399  Abort ();
350400}
351401
@@ -528,6 +578,9 @@ static void ReportFatalException(Environment* env,
528578
529579[[noreturn]] void  OOMErrorHandler (const  char * location,
530580                                  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 );
531584  const  char * message =
532585      details.is_heap_oom  ? " Allocation failed - JavaScript heap out of memory" 
533586                          : " Allocation failed - process out of memory" 
0 commit comments