swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
66.76k stars 10.29k forks source link

Runtime memory corruption regression in Swift 5.8 #65757

Open anlaital opened 1 year ago

anlaital commented 1 year ago

Description

There is seemingly random runtime memory corruption happening in our iOS application when it's build with Swift 5.8 (Xcode 14.3). The corruption happens when the application is compiled with optimisations (-O) enabled and no longer occurs when optimisations are disabled (-Onone). I have not tested if similar corruption can be reproduced with -Osize.

There seems to be regression between Swift 5.7.2 (Xcode 14.2) and Swift 5.8 (Xcode 14.3) as the memory corruption started happening straight after updating.

Steps to reproduce

Unfortunately I am unable to provide steps to reproduce as the project where this issue manifests is quite large and complex, so I'm not able to isolate a repro case for it at this time.

Expected behavior

Runtime memory corruption should not happen when optimisations are enabled.

Environment

keith commented 1 year ago

I think without a repro case it'll be hard to get anywhere with a fix here unfortunately 😞

anlaital commented 1 year ago

I tested this using -Osize Swift optimisations and the corruption happens with it as well.

@keith as I'm able to reproduce this with our unit tests I can help try narrow down where exactly the regression might be. If you have some things you'd like me to try I'm more than willing to do so!

ninoreiter commented 1 year ago

I experienced the same issue after I updated to Xcode 14.3 (swiftlang-5.8.0.124.2 clang-1403.0.22.11.100). Currently, I use swift-driver version: 1.75.2 Apple Swift version 5.8.1 (swiftlang-5.8.0.124.5 clang-1403.0.22.11.100), but the issue persists. The iOS app crashes with EXC_BAD_ACCESS / KERN_INVALID_ADDRESS. In my case this occurred only when accessing static stored properties but only under some conditions. Changing those to computed properties prevents the app from crashing.

Besides the crash, sometimes a wrong value is returned. In my case

struct AppEnvironment {
    static let platformID: UUID = UUID(uuidString: "0cba3773-7675-44ce-86e3-19a191274ce8") 
}
...
print(AppEnvironment.platformID.uuidString) // sometimes returns something different

I found an SwiftUI example to reproduce this in Preview and iOS Simulator. It doesn't seem to be related to SwiftUI only but is a general conflict between statically defined properties and/or globally defined variables.

import SwiftUI

// Running on iOS Simulator will crash at @main
// Running in Preview crashes with message "failed to demangle witness for associated type 'Body' in conformance '__lldb_expr_112.AppView: View' from mangled name '' - TypeDecoder.h:1312: Node kind 200 "" - unexpected kind"

@main
struct CrashTestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

// Making this a computed property works!
let Logo: some View = Image(systemName: "square.fill")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .frame(width: 200)

// If put above Logo-assignment, it works!
struct AppEnvironment {
    // Making this a computed property works!
    static let appGroupPlatform: String = "group.myapp"
    static let appID: UUID = UUID(uuidString: "c37bc963-2f75-4927-b34e-4fa3db87bece")!
}

struct ContentView: View {
    @State var counter = 0
    var body: some View {
        VStack {
            // Access works first time but crashes after reload.
            // Without, it won't crash.
            Text(AppEnvironment.appGroupPlatform)

            // Access works first time but changes the value after reload.
            Text(AppEnvironment.appID.uuidString)

            // Needed to make the app crash
            // Without, it won't crash.
            Logo

            // Something to reload the view
            Group {
                Text("\(counter)")
                Button("Reload View") {
                    counter += 1
                }
            }
        }
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}