If you suspect stack overflow happening and for some reason don't trust Xcode diagnostic tools catching those (seems unlikely ), you may use this manual "checkStack" call every here and there:
func checkStack(param: Any) {
var x: UInt8 = 1
func approximateSP(_ p: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer {
p
}
let sp = approximateSP(&x)
let top = pthread_get_stackaddr_np(pthread_self())
let size = pthread_get_stacksize_np(pthread_self())
let bottom = top - size
let safetySize = min(10*1024, size / 10)
let safeBottom = bottom + safetySize // "relatively" safe stack bottom
#if ENABLE_PRINTOUT
print("top : \(top)")
print("SP : \(sp) (approximate)")
print("safe : \(safeBottom) (relatively safe bottom)")
print("bottom : \(bottom)")
print("size : \(size)")
print("used : \(top - sp) [\(100*(top - sp)/size)%]")
print("param : \(param)")
print()
#endif
precondition(sp > safeBottom && sp <= top, "stack is about to overflow \(sp - bottom) bytes left, depth: \(param)")
}
func testRecursion(level: Int = 0) {
checkStack(param: level)
testRecursion(level: level + 1)
}
testRecursion()
With printout enabled it prints something like:
top : 0x000000016ddfc000
SP : 0x000000016dca9c77 (approximate)
safe : 0x000000016d602800 (relatively safe bottom)
bottom : 0x000000016d600000
size : 8372224
used : 1385353 [16%]
param : 17197
and with / without printout it checks available stack space and warns you if you are about to crash it with this:
failed: stack is about to overflow 10231 bytes left, depth: 104405
In the above for the safety margin I'm using the minimum of these two numbers: 10K and 10% of total stack size, adjust this according to your needs.
Edit: and when in lldb you can use the same calls:
(lldb) p pthread_get_stackaddr_np(pthread_self())
(UnsafeMutableRawPointer) $R0 = 0x16d600000
(lldb) p pthread_get_stacksize_np(pthread_self())
(Int) $R1 = 8372224