@@ -32,22 +32,41 @@ private struct TraceEntry: CustomStringConvertible {
3232 }
3333}
3434
35- var stderr = FileHandle . standardError
35+ // HACK: This array must be pre-allocated and contains functionally immortal
36+ // C-strings because String may allocate when passed to write(1).
37+ var registeredSignalInfo =
38+ UnsafeMutableBufferPointer < SigHandler > ( start:
39+ UnsafeMutablePointer . allocate ( capacity: killSigs. count) ,
40+ count: killSigs. count)
41+ var numRegisteredSignalInfo = 0
3642
3743/// A class managing a stack of trace entries. When a particular thread gets
3844/// a kill signal, this handler will dump all the entries in the tack trace and
3945/// end the process.
4046private class PrettyStackTraceManager {
47+ struct RawStackEntry {
48+ let data : UnsafeMutablePointer < Int8 >
49+ let count : Int
50+ }
51+
4152 /// Keeps a stack of serialized trace entries in reverse order.
42- /// - Note: This keeps strings, because it's not particularly safe to
53+ /// - Note: This keeps strings, because it's not safe to
4354 /// construct the strings in the signal handler directly.
44- var stack = [ Data] ( )
45- let stackDumpMsgData = " Stack dump: \n " . data ( using: . utf8) !
55+ var stack = [ RawStackEntry] ( )
56+
57+ private let stackDumpMsg : RawStackEntry
58+ init ( ) {
59+ let msg = " Stack dump: \n "
60+ stackDumpMsg = RawStackEntry ( data: strndup ( msg, msg. count) ,
61+ count: msg. count)
62+ }
4663
4764 /// Pushes the description of a trace entry to the stack.
4865 func push( _ entry: TraceEntry ) {
4966 let str = " \( entry. description) \n "
50- stack. insert ( str. data ( using: . utf8) !, at: 0 )
67+ let entry = RawStackEntry ( data: strndup ( str, str. count) ,
68+ count: str. count)
69+ stack. insert ( entry, at: 0 )
5170 }
5271
5372 /// Pops the latest trace entry off the stack.
@@ -59,9 +78,15 @@ private class PrettyStackTraceManager {
5978 /// Dumps the stack entries to standard error, starting with the most
6079 /// recent entry.
6180 func dump( _ signal: Int32 ) {
62- stderr. write ( stackDumpMsgData)
63- for entry in stack {
64- stderr. write ( entry)
81+ write ( STDERR_FILENO, stackDumpMsg. data, stackDumpMsg. count)
82+ let stackLimit = stack. count
83+ stack. withUnsafeBufferPointer { buffer in
84+ var i = 0
85+ while i < stackLimit {
86+ let bufItem = buffer [ i]
87+ write ( STDERR_FILENO, bufItem. data, bufItem. count)
88+ i += 1
89+ }
6590 }
6691 }
6792}
@@ -112,38 +137,43 @@ struct SigHandler {
112137 var signalNumber : Int32
113138}
114139
115- /// The currently registered set of signal handlers.
116- private var handlers = [ SigHandler] ( )
117-
118140/// Registers the pretty stack trace signal handlers.
119141private func registerHandler( signal: Int32 ) {
120142 var newHandler = SigAction ( )
121- newHandler. __sigaction_u. __sa_handler = {
143+ newHandler. __sigaction_u. __sa_handler = { signalNumber in
122144 unregisterHandlers ( )
123145
124146 // Unblock all potentially blocked kill signals
125147 var sigMask = sigset_t ( )
126148 sigfillset ( & sigMask)
127149 sigprocmask ( SIG_UNBLOCK, & sigMask, nil )
128150
129- threadLocalHandler ( ) . dump ( $0 )
130- exit ( - 1 )
151+ threadLocalHandler ( ) . dump ( signalNumber )
152+ exit ( signalNumber )
131153 }
132154 newHandler. sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK
133155 sigemptyset ( & newHandler. sa_mask)
134156
135157 var handler = SigAction ( )
136158 if sigaction ( signal, & newHandler, & handler) != 0 {
137159 let sh = SigHandler ( action: handler, signalNumber: signal)
138- handlers . append ( sh )
160+ registeredSignalInfo [ numRegisteredSignalInfo ] = sh
139161 }
140162}
141163
142164/// Unregisters all pretty stack trace signal handlers.
143165private func unregisterHandlers( ) {
144- while var handler = handlers. popLast ( ) {
145- sigaction ( handler. signalNumber, & handler. action, nil )
166+ var i = 0
167+ while i < killSigs. count {
168+ sigaction ( registeredSignalInfo [ i] . signalNumber,
169+ & registeredSignalInfo[ i] . action, nil )
170+ i += 1
146171 }
172+
173+ // HACK: Must leak the old registerdSignalInfo because we cannot safely
174+ // free inside a signal handler.
175+ // cannot: free(registeredSignalInfo)
176+ numRegisteredSignalInfo = 0
147177}
148178
149179/// A reference to the previous alternate stack, if any.
0 commit comments