Potential for stack overflow with large app states #488
Replies: 6 comments 4 replies
-
We've hit something like this before in isowords, where we were using a recursive data structure to hold onto the cube state. We modeled the 3-by-3 game cube using struct Three<A> {
var first: A
var second: A
var third: A
} Just a triply-nested one of these was enough to crash our app, though we're not sure if the issue was stack size. Our solution was to box these fields in an array: https://github.com/pointfreeco/isowords/blob/f77002115e1344d945345ac17c3e3f4ffe0b753b/Sources/SharedModels/Three.swift#L55 It's a blunt tool to do the job and introduced some potential for runtime crashes if we ever index outside expected bounds, but has worked well enough for us. Would definitely be interested in your wrapper type if that helps. I also wonder if a property wrapper could strategically be used for this kind of thing? @Heap // Game state is rather large, store it on the heap
var gameState: GameState |
Beta Was this translation helpful? Give feedback.
-
I too have run into similar cryptic crashes from somewhat large substates. @mluisbrown would you mind sharing the COW strategy you have been using? Aka, how did you decide which structs to use COW and what COW implementation did you use? Using a super simple Box type for some substates (without explicit custom COW) seemed to help us get passed a certain level, but we are still occasionally seeing these crashes as the state grows. |
Beta Was this translation helpful? Give feedback.
-
I wanted to mention that the way this showed up in my app was EXC_BAD_ACCESS crashes during certain app flows only on device. Using |
Beta Was this translation helpful? Give feedback.
-
Hi, we did get a similar bug(EXC_BAD_ACCESS) that happen only on device in our app and spent a good amount of time on it with DTS. What we find is that passing a certain threshold(between 22Kb and 26Kb) of a type size iOS will stack overflow thus EXC_BAD_ACCESS. For us it append the first time func bytesFormater(bytes: Int) -> String {
let bf = ByteCountFormatter()
bf.allowedUnits = .useAll
bf.countStyle = .file
bf.includesUnit = true
bf.isAdaptive = true
return bf.string(fromByteCount: Int64(bytes))
}
print("AppState size: \(bytesFormater(bytes: MemoryLayout.size(ofValue: state)))") Hope it helps, |
Beta Was this translation helpful? Give feedback.
-
Another source of stack overflow is For example, you might walk through an IdentifiedArray of substates and calculate a cancellation effect for those states that need to be cancelled, and returning a Changing to a |
Beta Was this translation helpful? Give feedback.
-
FYI https://forums.swift.org/t/willset-causing-copy-on-write-types-to-copy-on-mutations/52103 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
It seems that there is a potential with TCA to run into a stack overflow if the AppState / RootState becomes large enough.
In the project I'm working on we are using the ReactiveSwift fork of TCA and we had one sub state of the App State that was huge, around 8KB. With reactive frameworks and uni-directional data flow frameworks like TCA, ReSwift etc it's common to have quite a lot of stack frames.
The stack size on iOS is 1MB, so with a large enough app state, it's not that difficult to get into a stack overflow situation. In our case our app was only crashing on device, not in the simulator. That is because on macOS (simulator) the stack size is much larger: 8MB.
I posted about this on the Swift Forums too: https://forums.swift.org/t/possible-compiler-bug-related-to-deeply-nested-enums/47241
Our solution was to use a copy on write wrapper for the larger properties of the problematic states so that they are stored I the heap and not on the stack.
I'm just throwing this out there as it could be a problem that other people will face. Certainly with ReactiveSwift you can get a pretty big number of stack frames (over 100). I'm no sure if the same is true of Combine.
This issue also affects ReSwift, as can be seen here: https://bugs.swift.org/browse/SR-11093
Curious to know if others have seen this, and what mitigations you might have used.
Beta Was this translation helpful? Give feedback.
All reactions