@@ -18,35 +18,37 @@ using namespace node;
18
18
19
19
#define STDERR_FD 2
20
20
21
+ static Persistent<Function> callback;
22
+ static bool handlersSet = false ;
23
+
21
24
static void segfault_handler (int sig, siginfo_t *si, void *unused) {
22
25
void *array[32 ]; // Array to store backtrace symbols
23
26
size_t size; // To store the size of the stack backtrace
24
27
char sbuff[128 ];
25
28
int n; // chars written to buffer
26
- int fd;
27
- time_t now;
28
29
int pid;
29
30
30
- // Construct a filename
31
- time (&now);
32
31
pid = getpid ();
33
- snprintf (sbuff, sizeof (sbuff), " stacktrace-%d-%d.log" , (int )now, pid );
34
32
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 );
40
34
write (STDERR_FD, sbuff, n);
41
35
42
- // Write the Backtrace
43
36
size = backtrace (array, 32 );
44
- if (fd > 0 ) backtrace_symbols_fd (array, size, fd);
45
37
backtrace_symbols_fd (array, size, STDERR_FD);
46
38
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 );
50
52
}
51
53
52
54
// create some stack frames to inspect from CauseSegfault
@@ -62,7 +64,6 @@ void segfault_stack_frame_1()
62
64
int *foo = (int *)1 ;
63
65
printf (" NodeSegfaultHandlerNative: about to dereference NULL (will cause a SIGSEGV)\n " );
64
66
*foo = 78 ; // trigger a SIGSEGV
65
-
66
67
}
67
68
68
69
__attribute__ ((noinline))
@@ -80,13 +81,34 @@ Handle<Value> CauseSegfault(const Arguments& args) {
80
81
}
81
82
82
83
Handle <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 ());
90
112
}
91
113
92
114
extern " C" {
0 commit comments