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

FFI: Crash on iOS in RoomList.entries_with_dynamic_adapters #4774

Open
fl0lli opened this issue Mar 9, 2025 · 1 comment
Open

FFI: Crash on iOS in RoomList.entries_with_dynamic_adapters #4774

fl0lli opened this issue Mar 9, 2025 · 1 comment

Comments

@fl0lli
Copy link

fl0lli commented Mar 9, 2025

Similar to #4009, I encounter an EXC_BAD_ACCESS crash using the FFI bindings for iOS.
Tried using the simulator and real devices, no difference. Used the current latest main branch.

The stacktrace indicates it could again be a problem in the poll method for rooms_stream, where the clone method throws an error for fetch_add.

I built the Swift package using cargo xtask swift build-framework --target aarch64-apple-ios --target aarch64-apple-ios-sim (as a result of #4009 the build defaults to the reldbg profile, as seen in the log).

My example code is the following:

import SwiftUI
import MatrixRustSDK

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
        .onAppear(perform: doLoginAndFetchMessages)
    }
    
    private func doLoginAndFetchMessages() {
        Task {
            do {
                let client = try await ClientBuilder()
                    .serverNameOrHomeserverUrl(serverNameOrUrl: "http://127.0.0.1:8008")
                    .slidingSyncVersionBuilder(versionBuilder: .discoverNative)
                    .sessionPaths(dataPath: URL.applicationSupportDirectory.path(percentEncoded: false), cachePath: URL.cachesDirectory.path(percentEncoded: false))
                    .build()
                
                if let userId = UserDefaults.standard.string(forKey: "matrix-client-swift.user-id") {
                    let restoredSession = try MatrixClientSessionDelegate.shared.retrieveSessionFromKeychain(userId: userId)
                    try await client.restoreSession(session: restoredSession)
                } else {
                    try await client.login(username: "admin", password: "admin", initialDeviceName: nil, deviceId: nil)
                    let session = try client.session()
                    MatrixClientSessionDelegate.shared.saveSessionInKeychain(session: session)
                    UserDefaults.standard.set(session.userId, forKey: "matrix-client-swift.user-id")
                }
                
                let syncService = try await client.syncService().finish()
                await syncService.start()
                
                let listener = AllRoomsListener() { roomListItems in
                    print("roomListItems=\(roomListItems)")
                }
                
                let roomListService = syncService.roomListService()
                
                let handle = try await roomListService.allRooms().entriesWithDynamicAdapters(pageSize: 10, listener: listener)
                
                let _ = handle.controller().setFilter(kind: .joined)
            } catch {
                print("error: \(error)")
            }
        }
    }
}

class AllRoomsListener: RoomListEntriesListener {
    let onGetRoomsCallback: ([RoomListItem]) -> Void
    
    init(onGetRoomsCallback: @escaping ([RoomListItem]) -> Void) {
        self.onGetRoomsCallback = onGetRoomsCallback
    }
    
    func onUpdate(roomEntriesUpdate: [MatrixRustSDK.RoomListEntriesUpdate]) {
        for update in roomEntriesUpdate {
            switch update {
            case .reset(values: let values):
                onGetRoomsCallback(values)
            default:
                break // Handle all the other cases accordingly.
            }
        }
    }
}

One thing to note is that on the first run (no saved user, user logging in manually) the RoomListEntriesListener returns a reset (expected) with no items (?). The crash only happens on the second run, but does not appear to be caused by the session restoration, as a deviceId hard-coding also produces this crash (initial login, save deviceId and hard-code it into client.login()).

Edit:

  • If sessionPaths is not specified in the ClientBuilder constructor, the app does not crash, but the RoomListEntriesListener does not receive any Rooms.
  • Using element-hq/matrix-rust-components-swift v25.3.6 (currently newest) or building in release (--release) also crashes, but with The file path does not exist on the file system: /rustc/xxx/library/alloc/src/boxed.rs (the error nonetheless is located in Client.rooms_stream, so this may be an expected error message).
  • As described in RoomList.entries_with_dynamic_adapters if the call to setFilter is omitted, the app does not crash, as it does nothing.
  • Using element-hq/element-web I created a private, public and DM room with the users "admin" and "test".
@Hywan
Copy link
Member

Hywan commented Mar 10, 2025

Thanks for the bug report.

@stefanceriu Did you experience something similar?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants