Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-11093] EXC_BAD_ACCESS with large structs #53485

Closed
swift-ci opened this issue Jul 9, 2019 · 9 comments
Closed

[SR-11093] EXC_BAD_ACCESS with large structs #53485

swift-ci opened this issue Jul 9, 2019 · 9 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software run-time crash Bug → crash: Swift code crashed during execution

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Jul 9, 2019

Previous ID SR-11093
Radar rdar://problem/52894548
Original Reporter bmclachlin (JIRA User)
Type Bug
Status Resolved
Resolution Invalid
Environment
  • Xcode 10.2.1

  • iOS 12.3.1

  • iPhone 6 - MG3C2CL/A

  • Swift 5.0

  • mac OS 10.14.5 (18F132)

  • Debug

  • CocoaPods 1.7.3

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, RunTimeCrash
Assignee None
Priority Medium

md5: 844bfcd5ba16794536a9d3fae73ae39d

Issue Description:

Getting an EXC_BAD_ACCESS with large structs, but have only been able to replicate it with the ReSwift package. I originally posted my issue in their repo, but they advised me to post the issue here as well. ReSwift/ReSwift#237

public var state: State! 

public required init(
    reducer: @escaping Reducer<State>,
    state: State?,
    middleware: [Middleware<State>] = [],
    automaticallySkipsRepeats: Bool = true
) {
    ...

    if let state = state {
        self.state = state
    } else {
        dispatch(ReSwiftInit()) // This is called on init since I am not passing in state
    }
}

open func _defaultDispatch(action: Action) {
   ...

    isDispatching = true
    let newState = reducer(action, state) // state is nil with a smaller struct, but EXC_BAD_ACCESS with a larger struct
    isDispatching = false

    state = newState
}

This issue only happens on device in debug mode, works fine in the simulator.

I have created a sample repository that replicates the issue. https://github.com/brianmclachlin/exc-bad-access

Project uses CocoaPods to install ReSwift. ReSwift initializes in the AppDelegate, so all you need to do is run the app.

struct AppState: StateType {
    var oneState: OneState
    var twoState: TwoState
    var threeState: ThreeState
    var fourState: FourState
    var fiveState: FiveState
    ...
    var fourtySixState: FourtySixState
    var fourtySevenState: FourtySevenState
    var fourtyEightState: FourtyEightState
    var fourtyNineState: FourtyNineState
    var fiftyState: FiftyState
}

If you remove half of the sub-states from AppState and AppReducer then you will not get the error.

@belkadan
Copy link
Contributor

belkadan commented Jul 9, 2019

@eeckstein, aschwaighofer@apple.com (JIRA User), does this sound familiar? Note that they're using Swift 5.0.

@eeckstein
Copy link
Member

It could be a new issue. We had some problems with large structs in the past, but AFAIK, those were fixed in Swift 5.0.

@swift-ci
Copy link
Collaborator Author

Comment by Brian McLachlin (JIRA)

ReSwift/ReSwift.xcodeproj/project.pbxproj has the SWIFT_VERSION as 4.2. I'll see if I can get them to update to 5.0 and then verify that it's still an issue.

@swift-ci
Copy link
Collaborator Author

Comment by Malcolm Jarvis (JIRA)

bmclachlin (JIRA User) The example project you've linked here is already using Swift 5.0 for both your app target and ReSwift. I'll update your environment description appropriately.

@swift-ci
Copy link
Collaborator Author

Comment by Brian McLachlin (JIRA)

Thanks for clearing this up mjarvis (JIRA User), I guess it is in fact an issue with Swift 5.0.

@belkadan
Copy link
Contributor

@swift-ci create

@eeckstein
Copy link
Member

The crash is a stack overflow.
The AppState struct is 40KB large. That is not good, but would not cause a stack overflow by its own. But in the appReducer function, the compiler has to allocate a lot of such large temporary objects on the function stack frame for this large constructor call. This just exceeds the maximum available stack space.

Is it possible that you rewrite your code, e.g. use classes or copy-on-write data structures (implemented with classes) instead of plain structs?

@swift-ci
Copy link
Collaborator Author

Comment by Brian McLachlin (JIRA)

I have it working by putting a guard in to unwrap the state.

guard let state = state else {
    return AppState(
        userState: userReducer(action: action, state: nil),
        profileState: profileReducer(action: action, state: nil),
        ...
    )
}

return AppState(
    userState: userReducer(action: action, state: state.userState),
    profileState: profileReducer(action: action, state: state.profileState),
    ...
)

I assume this works because the optional `state?.` was creating a bunch of temporary objects where unwrapping it does not.

Why does the original code with the optionals work in Release, but not in Debug? I modified the Apple Clang and Swift Compiler Code Generation Optimization Level on Debug to match Release, but it still breaks.

@eeckstein
Copy link
Member

In release mode the compiler is probably able to optimize away some of the temporary values, which then reduces the required stack frame size.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added the crash Bug: A crash, i.e., an abnormal termination of software label Dec 12, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself crash Bug: A crash, i.e., an abnormal termination of software run-time crash Bug → crash: Swift code crashed during execution
Projects
None yet
Development

No branches or pull requests

4 participants