CBLite 1.4 - Crash found on [CBLSavedRevision documentID] and [CBLCache addResource:]

Hi,

Crash found in two different cases, but which is not consistently reproducing.

Background
We are trying to query from Couchbade DB using backgroundTellDatabaseNamed API. As per the documentation
“As a convenience, CBLManager’s backgroundTellDatabaseNamed:to: method will run a block on an existing background thread (the same one the replicator runs on). You must be careful to avoid using any of the calling thread’s objects in the block, since the block runs on a different thread. Instead, you should use the CBLDatabase object passed to the block and derive other objects like documents from it.”

So we are using the database object given in the backgroundTellDatabaseNamed block and performing the createQuery operation on the same object.

Sample Code

public func fetchAllOpenNotifications(callback: @escaping (_ documents: [OpenNotification]?) → Void) {
self.database.manager.backgroundTellDatabaseNamed(database.name) { database in
guard let query = database.existingViewNamed(viewName)?.createQuery() else {
callback(nil)
return
}
query.prefetch = true
query.runAsync({ (enumeratorResult, error) in
let documents = enumeratorResult.compactMap({ ($0 as? CBLQueryRow)?.document })
var openNotifications = OpenNotification
for document in documents {
openNotifications.append(OpenNotification(latitude: document.latitudeLongitude.0,
longitude: document.latitudeLongitude.1,
documentID: document.documentID, // Stack trace was pointing to this line on first crash
notificationNumber: document.notificationNumber))
}
callback(openNotifications)
})
}
}

We are observing the below-given crashes here.

Crash 1.
-[CBLSavedRevision documentID]: unrecognized selector sent to instance 0x2885a3840

CoreFoundation 0x209209ea4 0x2090ed000 + 1167012
libobjc.A.dylib 0x2083d9a50 0x2083d3000 + 27216
CoreFoundation 0x209122b14 0x2090ed000 + 219924
CoreFoundation 0x20920f7bc 0x2090ed000 + 1189820
CoreFoundation 0x20921146c 0x2090ed000 + 1197164
myApp MyAppStackclosure #in closure #1 in closure #1 in callback(_:slight_smile: (in myApp) (MyApp Stack.swift:307)
MyApp $SIeg_IeyB_TR (in MyApp) (:0)
Foundation 0x209c998bc 0x209b82000 + 1145020
Foundation 0x209ba1ab8 0x209b82000 + 129720
Foundation 0x209ba0f8c 0x209b82000 + 126860
Foundation 0x209c9b790 0x209b82000 + 1152912
libdispatch.dylib 0x208bef198 0x208be1000 + 57752
libdispatch.dylib 0x208c42484 0x208be1000 + 398468
libdispatch.dylib 0x208be582c 0x208be1000 + 18476
libdispatch.dylib 0x208be4fb0 0x208be1000 + 16304
libdispatch.dylib 0x208bf1a18 0x208be1000 + 68120
libdispatch.dylib 0x208bf22c0 0x208be1000 + 70336
libsystem_pthread.dylib 0x208e2517c 0x208e19000 + 49532
libsystem_pthread.dylib 0x208e27cec 0x208e19000 + 60652

Crash 2:
SIGABRT

libsystem_kernel.dylib 0x23087b104 0x230858000 + 143620
libsystem_c.dylib 0x2307d2d78 0x23077b000 + 359800
libsystem_malloc.dylib 0x2308cf768 0x2308b1000 + 124776
libsystem_malloc.dylib 0x2308cf924 0x2308b1000 + 125220
libsystem_malloc.dylib 0x2308c22d4 0x2308b1000 + 70356
Foundation 0x2316710c8 0x23165e000 + 78024
Foundation 0x231662df0 0x23165e000 + 19952
MyApp -[CBLCache addResource:] (in MyApp) (CBLCache.m:58)
MyApp -[CBLDatabase documentWithID:mustExist:isNew:] (in MyApp) (CBLDatabase.m:0)
MyApp -[CBLQueryRow document] (in MyApp) (CBLQueryRow.m:0)
MyApp MyAppyAppStackclosure #in closure #1 in closure #1 in callback(_:slight_smile: (in MyApp) (:0)
MyApp $SIeg_IeyB_TR (in MyApp) (:0)

Please help us to figure out this issues

I don’t think the “document” property is persistent throughout the iteration but I’m not sure. If it is it means you cannot flatten the query like that. @jens or @pasin does this look like something that should work?

I don’t understand how you can access custom properties like latitudeLongitude or notificationNumber on a CBLDocument object. Is this real code that compiles?

(also, note that Couchbase Lite 1.4 is nearly at the end of its support lifespan, and no one on the team has worked on it much in years…)

Yes, this code will compile with the help of a CBLExtension through whcih we can capture the custom properties.

Found like one of the crashes (crash 2) is pointing to this line. Now we know accessing the document like this will cause for some memory issue. But still, the crash log showing its something else. Any idea on this?
(Note: we are about to migrate to latest couchbase version. But until that we have to support the existing one)

What are the symbols (function/method names) for the stack frames in Foundation and CoreFoundation? Those should be present in any crash report.

Please let me know if this works.

02%20AM

That’s just the same information you posted earlier, again without any symbols. I don’t know where you’re getting these crash logs from, but it should be able to provide the symbols for you. If it’s a 3rd party service like Crashlytics, look at their documentation or ask their support.

We integrated AppDynamics for analytics and got the crash log as below,

Thread 43 Crashed:

0   Foundation                     0x000000019b206758 readPointerAt + 0
1   Foundation                     0x000000019b0f8fd8 -[NSConcreteMapTable grow] + 500
2   Foundation                     0x000000019b0eadec -[NSConcreteMapTable setObject:forKey:] + 164
3   Construct                      0x000000010082eb40 -[CBLCache addResource:] (CBLCache.m:57)
4   Construct                      0x000000010082d9c8 -[CBLDatabase documentWithID:mustExist:isNew:] (CBLDatabase.m:336)
5   Construct                      0x000000010086e8a4 -[CBLQueryRow document] (CBLQueryRow.m:268)
6   Construct                      0x00000001006d7928 closure #1 () -> () in closure #1 (__C.CBLQueryEnumerator, Swift.Error) -> () in closure #1 (__C.CBLDatabase) -> () in Construct.ConstructStack.fetchAllOpenNotifications(callback: ([Construct.OpenNotification]?) -> ()) -> () (ConstructStack.swift:302)
7   Construct                      0x000000010054aef0 reabstraction thunk helper from @escaping @callee_guaranteed () -> () to @escaping @callee_unowned @convention(block) () -> () (<compiler-generated>:0)
8   Foundation                     0x000000019b1fd8b8 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
9   Foundation                     0x000000019b105ab4 -[NSBlockOperation main] + 68
10  Foundation                     0x000000019b104f88 -[__NSOperationInternal _start:] + 736
11  Foundation                     0x000000019b1ff78c __NSOQSchedule_f + 268
12  libdispatch.dylib              0x000000019a153194 _dispatch_block_async_invoke2 + 100
13  libdispatch.dylib              0x000000019a1a6480 _dispatch_client_callout + 12
14  libdispatch.dylib              0x000000019a149828 _dispatch_continuation_pop$VARIANT$mp + 408
15  libdispatch.dylib              0x000000019a148ef0 _dispatch_async_redirect_invoke + 596
16  libdispatch.dylib              0x000000019a155a14 _dispatch_root_queue_drain + 372
17  libdispatch.dylib              0x000000019a1562bc _dispatch_worker_thread2 + 124
18  libsystem_pthread.dylib        0x000000019a389178 _pthread_wqthread + 468
19  libsystem_pthread.dylib        0x000000019a38bce8 start_wqthread + 0

For performing the query we used query.runAsync({ (enumeratorResult, error) in }).
Please see if this helps.

Also adding the log for another issue here.

*** Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘*** -[__NSArrayM insertObject:atIndex:]: index 13 beyond bounds [0 … 11]’

Last Exception Backtrace:
CoreFoundation 0x00000001c2505ea4 __exceptionPreprocess + 228
libobjc.A.dylib 0x00000001c16d5a4c objc_exception_throw + 52
CoreFoundation 0x00000001c247d380 _CFThrowFormattedException + 108
CoreFoundation 0x00000001c23ec7fc -[__NSArrayM insertObject:atIndex:] + 1240
Construct 0x0000000104732d58 -[CBLCache resourceWithCacheKey:] (CBLCache.m:74)
Construct 0x00000001047318cc -[CBLDatabase documentWithID:mustExist:isNew:] (CBLDatabase.m:319)
Construct 0x0000000104512df4 Construct.AttachmentDownloadOperation.start() → () (DataAccessManager.swift:129)
Construct 0x00000001045130c0 @objc Construct.AttachmentDownloadOperation.start() → () (:0)
Foundation 0x00000001c2f9778c __NSOQSchedule_f + 268
libdispatch.dylib 0x00000001c1f3d6c4 _dispatch_call_block_and_release + 20
libdispatch.dylib 0x00000001c1f3e480 _dispatch_client_callout + 12
libdispatch.dylib 0x00000001c1ee1828 _dispatch_continuation_pop$VARIANT$mp + 408
libdispatch.dylib 0x00000001c1ee0ef0 _dispatch_async_redirect_invoke + 596
libdispatch.dylib 0x00000001c1eeda14 _dispatch_root_queue_drain + 372
libdispatch.dylib 0x00000001c1eee2bc _dispatch_worker_thread2 + 124
libsystem_pthread.dylib 0x00000001c2121178 _pthread_wqthread + 468
libsystem_pthread.dylib 0x00000001c2123ce8 start_wqthread + 0

The log with symbols isn’t the same stack. It looks like a different issue. Looks like your app is calling into Couchbase Lite on a background thread via NSOperation. Is this call thread-safe? In Couchbase Lite 1.x you can’t use a CBLDatabase instance on multiple threads/queues.

There are two operations getting executed in the operation queue.

  1. Looping through the enumeration result and accessing documents
    enumeratorResult.compactMap({ ($0 as? CBLQueryRow)?.document })
  2. Creating a model object from this document properties

Do you think these two tasks will cause any CBLDatabase instance use? Query generation and executing the query to get enumeratorResult are performing outside the operation queue. Also I suspect the usage of query.runAsync({ (enumeratorResult, error) in }) here instead of using synchronous query query.run.

If prefetch is not on, then accessing the document from the query row is a database operation.

We have set query.prefetch = true before executing query.runAsync({ (enumeratorResult, error) in })