@@ -18,35 +18,37 @@ using namespace node;
1818
1919#define STDERR_FD 2
2020
21+ static Persistent<Function> callback;
22+ static bool handlersSet = false ;
23+
2124static void segfault_handler (int sig, siginfo_t *si, void *unused) {
2225 void *array[32 ]; // Array to store backtrace symbols
2326 size_t size; // To store the size of the stack backtrace
2427 char sbuff[128 ];
2528 int n; // chars written to buffer
26- int fd;
27- time_t now;
2829 int pid;
2930
30- // Construct a filename
31- time (&now);
3231 pid = getpid ();
33- snprintf (sbuff, sizeof (sbuff), " stacktrace-%d-%d.log" , (int )now, pid );
3432
35- // Open the File
36- fd = open (sbuff, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IRGRP | S_IROTH);
37- // Write the header line
38- n = snprintf (sbuff, sizeof (sbuff), " PID %d received SIGSEGV for address: 0x%lx\n " , pid, (long ) si->si_addr );
39- if (fd > 0 ) write (fd, sbuff, n);
33+ n = snprintf (sbuff, sizeof (sbuff), " PID %d received SIGSEGV/SIGBUS (%i) for address: 0x%lx\n " , pid, si->si_signo , (long )si->si_addr );
4034 write (STDERR_FD, sbuff, n);
4135
42- // Write the Backtrace
4336 size = backtrace (array, 32 );
44- if (fd > 0 ) backtrace_symbols_fd (array, size, fd);
4537 backtrace_symbols_fd (array, size, STDERR_FD);
4638
47- // Exit violently
48- close (fd);
49- exit (-1 );
39+ if (!callback.IsEmpty ()) {
40+ char **stack = backtrace_symbols (array, size);
41+ Local<Array> argStack = Local<Array>::New (Array::New (size));
42+ for (size_t i = 0 ; i < size; i++) {
43+ argStack->Set (i, String::New (stack[i]));
44+ }
45+ Local<Value> argv[3 ] = {argStack, Local<Value>::New (Number::New (si->si_signo )), Local<Value>::New (Number::New ((long )si->si_addr ))};
46+ callback->Call (Context::GetCurrent ()->Global (), 3 , argv);
47+ free (stack);
48+ }
49+
50+ // Re-send the signal, this time a default handler will be called
51+ kill (pid, si->si_signo );
5052}
5153
5254// create some stack frames to inspect from CauseSegfault
@@ -62,7 +64,6 @@ void segfault_stack_frame_1()
6264 int *foo = (int *)1 ;
6365 printf (" NodeSegfaultHandlerNative: about to dereference NULL (will cause a SIGSEGV)\n " );
6466 *foo = 78 ; // trigger a SIGSEGV
65-
6667}
6768
6869__attribute__ ((noinline))
@@ -80,13 +81,34 @@ Handle<Value> CauseSegfault(const Arguments& args) {
8081}
8182
8283Handle<Value> RegisterHandler (const Arguments& args) {
83- struct sigaction sa;
84- memset (&sa, 0 , sizeof (struct sigaction ));
85- sigemptyset (&sa.sa_mask );
86- sa.sa_sigaction = segfault_handler;
87- sa.sa_flags = SA_SIGINFO;
88- sigaction (SIGSEGV, &sa, NULL );
89- return Undefined ();
84+ HandleScope scope;
85+
86+ if (args.Length () > 0 ) {
87+ if (!args[0 ]->IsFunction ()) {
88+ ThrowException (Exception::TypeError (String::New (" Invalid callback argument" )));
89+ return scope.Close (Undefined ());
90+ }
91+
92+ if (!callback.IsEmpty ()) {
93+ callback.Dispose ();
94+ callback.Clear ();
95+ }
96+ callback = Persistent<Function>::New (Handle<Function>::Cast (args[0 ]));
97+ }
98+
99+ // Set our handler only once
100+ if (!handlersSet) {
101+ struct sigaction sa;
102+ memset (&sa, 0 , sizeof (struct sigaction ));
103+ sigemptyset (&sa.sa_mask );
104+ sa.sa_sigaction = segfault_handler;
105+ sa.sa_flags = SA_SIGINFO | SA_RESETHAND; // We set SA_RESETHAND so that our handler is called only once
106+ sigaction (SIGSEGV, &sa, NULL );
107+ sigaction (SIGBUS, &sa, NULL );
108+ handlersSet = true ;
109+ }
110+
111+ return scope.Close (Undefined ());
90112}
91113
92114extern " C" {
0 commit comments