@@ -32,22 +32,41 @@ private struct TraceEntry: CustomStringConvertible {
32
32
}
33
33
}
34
34
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
36
42
37
43
/// A class managing a stack of trace entries. When a particular thread gets
38
44
/// a kill signal, this handler will dump all the entries in the tack trace and
39
45
/// end the process.
40
46
private class PrettyStackTraceManager {
47
+ struct RawStackEntry {
48
+ let data : UnsafeMutablePointer < Int8 >
49
+ let count : Int
50
+ }
51
+
41
52
/// 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
43
54
/// 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
+ }
46
63
47
64
/// Pushes the description of a trace entry to the stack.
48
65
func push( _ entry: TraceEntry ) {
49
66
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 )
51
70
}
52
71
53
72
/// Pops the latest trace entry off the stack.
@@ -59,9 +78,15 @@ private class PrettyStackTraceManager {
59
78
/// Dumps the stack entries to standard error, starting with the most
60
79
/// recent entry.
61
80
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
+ }
65
90
}
66
91
}
67
92
}
@@ -112,38 +137,43 @@ struct SigHandler {
112
137
var signalNumber : Int32
113
138
}
114
139
115
- /// The currently registered set of signal handlers.
116
- private var handlers = [ SigHandler] ( )
117
-
118
140
/// Registers the pretty stack trace signal handlers.
119
141
private func registerHandler( signal: Int32 ) {
120
142
var newHandler = SigAction ( )
121
- newHandler. __sigaction_u. __sa_handler = {
143
+ newHandler. __sigaction_u. __sa_handler = { signalNumber in
122
144
unregisterHandlers ( )
123
145
124
146
// Unblock all potentially blocked kill signals
125
147
var sigMask = sigset_t ( )
126
148
sigfillset ( & sigMask)
127
149
sigprocmask ( SIG_UNBLOCK, & sigMask, nil )
128
150
129
- threadLocalHandler ( ) . dump ( $0 )
130
- exit ( - 1 )
151
+ threadLocalHandler ( ) . dump ( signalNumber )
152
+ exit ( signalNumber )
131
153
}
132
154
newHandler. sa_flags = SA_NODEFER | SA_RESETHAND | SA_ONSTACK
133
155
sigemptyset ( & newHandler. sa_mask)
134
156
135
157
var handler = SigAction ( )
136
158
if sigaction ( signal, & newHandler, & handler) != 0 {
137
159
let sh = SigHandler ( action: handler, signalNumber: signal)
138
- handlers . append ( sh )
160
+ registeredSignalInfo [ numRegisteredSignalInfo ] = sh
139
161
}
140
162
}
141
163
142
164
/// Unregisters all pretty stack trace signal handlers.
143
165
private 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
146
171
}
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
147
177
}
148
178
149
179
/// A reference to the previous alternate stack, if any.
0 commit comments