session-foundation / session-ios

A private messenger for iOS.
https://getsession.org
GNU General Public License v3.0
4 stars 1 forks source link

[BUG] Session iOS crashes when entering Communities with blinded ID disabled #77

Closed ghost closed 1 year ago

ghost commented 1 year ago

Code of conduct

Self-training on how to write a bug report

Is there an existing issue for this?

Current Behavior

When entering the Community "kat67world", Session iOS crashes and quits immediately.

Expected Behavior

Should not crash at all.

Steps To Reproduce

  1. Install Session iOS and create a fresh new account
  2. Join community Kat67 world http://45.77.102.159/kat67world?public_key=132d7cf93a6a72eabbf9357a3a29d0644b27b1166e12d36704a0785f7ccb0f74
  3. Click the conversation entry of "Kat67 world"

This results in a crash immediately.

I can reproduce with both Session 2.2.8 and Session 2.2.9 on my real devices. Multiple users reported this crash (when entering other Community with blinded ID disabled), and there are sophisticated users reporting they found a workaround by downgrading to Session 2.2.7.

Edited: I can also reproduce it with iOS simulator (must be a fresh created account)

iOS Version

iOS 16.3.1 / iOS 15.7.3

Session Version

Session 2.2.8 / Session 2.2.9

Anything else?

com.loki-project.loki-messenger 2023-04-01--02-45-33-077.log

ghost commented 1 year ago
session-ios/Pods/GRDB.swift/GRDB/Core/DatabasePool.swift:345: Fatal error: Database methods are not reentrant.
ghost commented 1 year ago
(lldb) bt
* thread oxen-io/session-ios#12, queue = 'GRDB.DatabasePool.reader.1', stop reason = Fatal error: Database methods are not reentrant.
    frame #0: 0x000000018bf1d8b0 libswiftCore.dylib`_swift_runtime_on_report
    frame oxen-io/session-ios#1: 0x000000018bfaa550 libswiftCore.dylib`_swift_stdlib_reportFatalErrorInFile + 204
    frame oxen-io/session-ios#2: 0x000000018bc596d4 libswiftCore.dylib`closure oxen-io/session-ios#1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure oxen-io/session-ios#1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 192
    frame oxen-io/session-ios#3: 0x000000018bc58598 libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.String, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 300
  * frame oxen-io/session-ios#4: 0x000000010792289c GRDB`GRDBPrecondition(condition=0x000000010770a22c GRDB`partial apply forwarder for implicit closure oxen-io/session-ios#1 () -> Swift.Bool in GRDB.DatabasePool.read<A>((GRDB.Database) throws -> A) throws -> A at <compiler-generated>, message=0x0000000107706054 GRDB`implicit closure oxen-io/session-ios#2 () -> Swift.String in GRDB.DatabasePool.read<A>((GRDB.Database) throws -> A) throws -> A at <compiler-generated>, file="/Users/qhong/src/session-ios/Pods/GRDB.swift/GRDB/Core/DatabasePool.swift", line=345) at Utils.swift:38:9
    frame oxen-io/session-ios#5: 0x0000000107705c4c GRDB`DatabasePool.read<T>(value=0x10c9a109c, self=0x000060000012c090) at DatabasePool.swift:345:9
    frame oxen-io/session-ios#6: 0x00000001077094b8 GRDB`protocol witness for DatabaseReader.read<A>(_:) in conformance DatabasePool at <compiler-generated>:0
    frame oxen-io/session-ios#7: 0x00000001095875c4 SessionUtilitiesKit`Storage.read<T>(value=0x10c9a109c, self=0x0000600001aef780) at Storage.swift:336:30
    frame oxen-io/session-ios#8: 0x000000010c9a056c SessionMessagingKit`static SessionThread.getUserHexEncodedBlindedKey(threadId="http://45.77.102.159.kat67world", threadVariant=openGroup, self=SessionMessagingKit.SessionThread) at SessionThread.swift:325:133
    frame oxen-io/session-ios#9: 0x000000010c6bf38c SessionMessagingKit`SessionThreadViewModel.populatingCurrentUserBlindedKey(currentUserBlindedPublicKeyForThisThread=nil, self=SessionMessagingKit.SessionThreadViewModel @ 0x00000001755e95b0) at SessionThreadViewModel.swift:412:58
    frame oxen-io/session-ios#10: 0x0000000104c9d150 Session`closure oxen-io/session-ios#2 in closure oxen-io/session-ios#1 in ConversationViewModel.setupObservableThreadData(viewModel=SessionMessagingKit.SessionThreadViewModel @ 0x00000001755e95b0, self=0x00000001268a2400) at ConversationViewModel.swift:148:35
    frame oxen-io/session-ios#11: 0x0000000104cab8c8 Session`partial apply for closure oxen-io/session-ios#2 in closure oxen-io/session-ios#1 in ConversationViewModel.setupObservableThreadData(for:) at <compiler-generated>:0
    frame oxen-io/session-ios#12: 0x000000018bc4cb28 libswiftCore.dylib`Swift.Optional.map<τ_0_0>((τ_0_0) throws -> τ_1_0) throws -> Swift.Optional<τ_1_0> + 240
    frame oxen-io/session-ios#13: 0x0000000104c9cb74 Session`closure oxen-io/session-ios#1 in ConversationViewModel.setupObservableThreadData(db=0x0000000125d17530, threadId="http://45.77.102.159.kat67world", self=0x00000001268a2400) at ConversationViewModel.swift:147:22
    frame oxen-io/session-ios#14: 0x0000000104cab6f0 Session`partial apply for closure oxen-io/session-ios#1 in ConversationViewModel.setupObservableThreadData(for:) at <compiler-generated>:0
    frame oxen-io/session-ios#15: 0x0000000107751724 GRDB`ValueReducers.Fetch._fetch(db=0x0000000125d17530, self=(__fetch = 0x0000000104cab6d0 Session`partial apply forwarder for closure oxen-io/session-ios#1 (GRDB.Database) throws -> Swift.Optional<SessionMessagingKit.SessionThreadViewModel> in Session.ConversationViewModel.setupObservableThreadData(for: Swift.String) -> GRDB.ValueObservation<GRDB.ValueReducers.RemoveDuplicates<GRDB.ValueReducers.Fetch<Swift.Optional<SessionMessagingKit.SessionThreadViewModel>>>> at <compiler-generated>)) at Fetch.swift:14:24
    frame oxen-io/session-ios#16: 0x0000000107751870 GRDB`protocol witness for _DatabaseValueReducer._fetch(_:) in conformance ValueReducers.Fetch<A> at <compiler-generated>:0
    frame oxen-io/session-ios#17: 0x00000001077fd7c0 GRDB`ValueReducers.RemoveDuplicates<>._fetch(db=0x0000000125d17530, self=GRDB.ValueReducers.RemoveDuplicates<GRDB.ValueReducers.Fetch<Swift.Optional<SessionMessagingKit.SessionThreadViewModel>>> @ 0x00000001755ebca0) at RemoveDuplicates.swift:50:18
    frame oxen-io/session-ios#18: 0x00000001077fd840 GRDB`protocol witness for _DatabaseValueReducer._fetch(_:) in conformance <> ValueReducers.RemoveDuplicates<A> at <compiler-generated>:0
    frame oxen-io/session-ios#19: 0x0000000107926968 GRDB`closure oxen-io/session-ios#1 in ValueConcurrentObserver.DatabaseAccess.fetch(self=GRDB.ValueConcurrentObserver<GRDB.ValueReducers.RemoveDuplicates<GRDB.ValueReducers.Fetch<Swift.Optional<SessionMessagingKit.SessionThreadViewModel>>>>.DatabaseAccess @ 0x00000001755ed4c0, db=0x0000000125d17530) at ValueConcurrentObserver.swift:89:29
    frame oxen-io/session-ios#20: 0x0000000107926a00 GRDB`partial apply for closure oxen-io/session-ios#1 in ValueConcurrentObserver.DatabaseAccess.fetch(_:) at <compiler-generated>:0
    frame oxen-io/session-ios#21: 0x000000010792396c GRDB`throwingFirstError<T>(execute=0x1079269d4, finally=0x00000001076afce0 GRDB`partial apply forwarder for implicit closure oxen-io/session-ios#2 () throws -> () in implicit closure oxen-io/session-ios#1 (GRDB.Database) -> () throws -> () in GRDB.Database.readOnly<A>(() throws -> A) throws -> A at <compiler-generated>) at Utils.swift:104:22
    frame oxen-io/session-ios#22: 0x00000001076a39e8 GRDB`Database.readOnly<T>(block=0x1079269d4, self=0x0000000125d17530) at Database.swift:575:20
    frame oxen-io/session-ios#23: 0x00000001076a7d54 GRDB`Database.isolated<T>(readOnly=true, block=0x1079269d4, self=0x0000000125d17530) at Database.swift:1019:33
    frame oxen-io/session-ios#24: 0x000000010792682c GRDB`ValueConcurrentObserver.DatabaseAccess.fetch(db=0x0000000125d17530, self=GRDB.ValueConcurrentObserver<GRDB.ValueReducers.RemoveDuplicates<GRDB.ValueReducers.Fetch<Swift.Optional<SessionMessagingKit.SessionThreadViewModel>>>>.DatabaseAccess @ 0x0000000127c0a3a0) at ValueConcurrentObserver.swift:88:20
    frame oxen-io/session-ios#25: 0x000000010792ffe4 GRDB`closure oxen-io/session-ios#2 in ValueConcurrentObserver.databaseDidCommit(db=0x0000000125d17530, databaseAccess=GRDB.ValueConcurrentObserver<GRDB.ValueReducers.RemoveDuplicates<GRDB.ValueReducers.Fetch<Swift.Optional<SessionMessagingKit.SessionThreadViewModel>>>>.DatabaseAccess @ 0x0000000127c0a3a0) at ValueConcurrentObserver.swift:524:36
    frame oxen-io/session-ios#26: 0x000000010793356c GRDB`partial apply for closure oxen-io/session-ios#2 in ValueConcurrentObserver.databaseDidCommit(_:) at <compiler-generated>:0
    frame oxen-io/session-ios#27: 0x0000000107707d74 GRDB`closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in DatabasePool.concurrentRead<T>(value=0x1079334f4, db=0x0000000125d17530) at DatabasePool.swift:454:66
    frame oxen-io/session-ios#28: 0x000000010770a910 GRDB`partial apply for closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in DatabasePool.concurrentRead<A>(_:) at <compiler-generated>:0
    frame oxen-io/session-ios#29: 0x0000000107707c78 GRDB`closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in DatabasePool.concurrentRead<T>(db=0x0000000125d17530, value=0x1079334f4) at DatabasePool.swift:454:53
    frame oxen-io/session-ios#30: 0x000000010770a694 GRDB`partial apply for closure oxen-io/session-ios#1 in closure oxen-io/session-ios#1 in DatabasePool.concurrentRead<A>(_:) at <compiler-generated>:0
    frame oxen-io/session-ios#31: 0x000000018bd8627c libswiftCore.dylib`Swift.Result.flatMap<τ_0_0>((τ_0_0) -> Swift.Result<τ_1_0, τ_0_1>) -> Swift.Result<τ_1_0, τ_0_1> + 252
    frame oxen-io/session-ios#32: 0x0000000107707acc GRDB`closure oxen-io/session-ios#1 in DatabasePool.concurrentRead<T>(dbResult=success, futureResult=nil, value=0x1079334f4, futureSemaphore=0x0000600002cbe1c0) at DatabasePool.swift:454:37
    frame oxen-io/session-ios#33: 0x0000000107708704 GRDB`closure oxen-io/session-ios#2 in DatabasePool.asyncConcurrentRead(db=0x0000000125d17530, releaseReader=0x00000001077d9a84 GRDB`partial apply forwarder for reabstraction thunk helper from @escaping @callee_guaranteed () -> (@out ()) to @escaping @callee_guaranteed () -> () at <compiler-generated>, isolationSemaphore=0x0000600002cbe760, value=0x0000000107709efc GRDB`partial apply forwarder for closure oxen-io/session-ios#1 (Swift.Result<GRDB.Database, Swift.Error>) -> () in GRDB.DatabasePool.concurrentRead<A>((GRDB.Database) throws -> A) -> GRDB.DatabaseFuture<A> at <compiler-generated>) at DatabasePool.swift:593:17
    frame oxen-io/session-ios#34: 0x000000010782a74c GRDB`closure oxen-io/session-ios#1 in SerializedDatabase.async(block=0x000000010770a9f4 GRDB`partial apply forwarder for closure oxen-io/session-ios#2 (GRDB.Database) -> () in GRDB.DatabasePool.asyncConcurrentRead((Swift.Result<GRDB.Database, Swift.Error>) -> ()) -> () at <compiler-generated>, self=0x000060000012c690) at SerializedDatabase.swift:195:13
    frame oxen-io/session-ios#35: 0x00000001077da234 GRDB`thunk for @escaping @callee_guaranteed () -> () at <compiler-generated>:0
    frame oxen-io/session-ios#36: 0x000000010c290594 libdispatch.dylib`_dispatch_call_block_and_release + 24
    frame oxen-io/session-ios#37: 0x000000010c291d5c libdispatch.dylib`_dispatch_client_callout + 16
    frame oxen-io/session-ios#38: 0x000000010c29a040 libdispatch.dylib`_dispatch_lane_serial_drain + 928
    frame oxen-io/session-ios#39: 0x000000010c29ad80 libdispatch.dylib`_dispatch_lane_invoke + 428
    frame oxen-io/session-ios#40: 0x000000010c2a8b40 libdispatch.dylib`_dispatch_workloop_worker_thread + 1720
    frame oxen-io/session-ios#41: 0x00000001ae55eb40 libsystem_pthread.dylib`_pthread_wqthread + 284
ghost commented 1 year ago

from ChatGPT:

This error is related to the GRDB.swift library, which is a Swift framework for SQLite databases. The error message "Fatal error: Database methods are not reentrant" indicates that a database method was called in a reentrant way, which is not supported by the GRDB.swift library. This can lead to issues like data corruption, deadlocks, or unexpected behavior, as the same resources may be accessed or modified concurrently.

The error occurs in a multithreaded environment, as shown by the thread oxen-io/session-ios#12 in the error message. The call stack provides more information about the sequence of method calls that led to the error. The problematic call occurs in the GRDB library at DatabasePool.swift:345. The error propagates through various frames of the call stack, including classes like SessionThread, SessionThreadViewModel, and ConversationViewModel from SessionUtilitiesKit and SessionMessagingKit.

To resolve this issue, you need to ensure that you're not calling any database methods from within other database methods that are still being executed. This may involve reorganizing your code to ensure that each method has completed its execution before calling another one.

In a multithreaded environment, you should also make sure that database access is properly synchronized to avoid race conditions and concurrency issues. You can use concurrency mechanisms like GCD (Grand Central Dispatch) or NSOperationQueue in Swift to ensure proper synchronization and prevent reentrant calls to the database methods.

ghost commented 1 year ago
static SessionThread.getUserHexEncodedBlindedKey(threadId="http://45.77.102.159.kat67world", threadVariant=openGroup, self=SessionMessagingKit.SessionThread) at SessionThread.swift:325:133

Seems related to the recent fix of quoted message in Community with blinded Id enabled, which creates a side effect of crashing in Community with blinded Id disabled.

@mpretty-cyro @RyanRory mind to have a look?

mpretty-cyro commented 1 year ago

Thanks for reporting this @fracting I've opened a PR which should fix the issue

ghost commented 1 year ago

Thanks for the quick fix! Confirming working for me in iPhone simulator. Will retest after next formal release.

@mpretty-cyro

mpretty-cyro commented 1 year ago

Resolved in oxen-io/session-ios#810, please let us know if this presents itself again once the official release is done

ghost commented 1 year ago

I think usually the common practice is to close an issue after a new official binary release is available in the app store, otherwise other users might repeatedly report the same bug.

I usually keep track of bugs I reported by myself and retest them after a new release is available, if the issue is closed before a new release, I might forget to retest.

ghost commented 1 year ago

Confirming fixed in Session iOS official app store release 2.2.10, thanks for the great work!