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

Crash in fleece::Scope [CBSE-6472] #712

Closed
snej opened this issue Feb 28, 2019 · 1 comment

Comments

@snej
Copy link
Member

commented Feb 28, 2019

In CBSE-6472, an iOS app is crashing when fleece::Scope throws an exception on a bg thread while updating a live query. This is in a recent custom build 2.5.0-SB3.

libc++abi.dylib: terminating with uncaught exception of type fleece::FleeceException: internal Fleece library error: Incompatible duplicate Scope 0x70000aa4b548 for (0x60003fbe2e20 .. 0x60003fbe2e22) with sk=0x7fa8778b8e00: conflicts with 0x70000a945d58 with sk=0x7fa87fe36c00

...
    frame #8: __clang_call_terminate + 11
  * frame #9: fleece::impl::Scope::registr(this=0x000070000aa4b548) at Doc.cc:104 [opt]
    frame #10: litecore::QueryFleeceScope::QueryFleeceScope(sqlite3_context*, sqlite3_value**) [inlined] fleece::impl::Scope::Scope(this=<unavailable>, sk=<unavailable>, destination=slice @ 0x00007f802d156400) at Doc.cc:49 [opt]
    frame #11: litecore::QueryFleeceScope::QueryFleeceScope(this=0x000070000aa4b548, ctx=<unavailable>, argv=<unavailable>) at SQLiteFleeceUtil.cc:128 [opt]
    frame #12: litecore::fl_value(sqlite3_context*, int, sqlite3_value**) [inlined] litecore::QueryFleeceScope::QueryFleeceScope(this=0x00007fa8778b8e00, ctx=<unavailable>, argv=<unavailable>) at SQLiteFleeceUtil.cc:130 [opt]
    frame #13: litecore::fl_value(ctx=0x00006000526c1840, argc=<unavailable>, argv=<unavailable>) at SQLiteFleeceFunctions.cc:59 [opt]
    frame #14: sqlite3VdbeExec(p=<unavailable>) at see-sqlite.c:89961 [opt]
    frame #15: sqlite3_step [inlined] sqlite3Step(p=<unavailable>) at see-sqlite.c:81040 [opt]
    frame #16: sqlite3_step(pStmt=0x00007fa7fe0e1ff0) at see-sqlite.c:81103 [opt]
    frame #17: SQLite::Statement::executeStep(this=0x00006000312ffde0) at Statement.cpp:258 [opt]
    frame #18: litecore::SQLiteQueryRunner::fastForward(this=0x000070000aa4c638) at SQLiteQuery.cc:430 [opt]
    frame #19: litecore::SQLiteQuery::createEnumerator(this=0x000060012cf89ef0, options=0x000060002089ef68, lastSeq=6382) at SQLiteQuery.cc:475 [opt]
    frame #20: litecore::SQLiteQueryEnumerator::refresh(this=0x000060002089ef40) at SQLiteQuery.cc:262 [opt]
    frame #21: C4QueryEnumeratorImpl::refresh(this=0x000060005dfafb10) at c4Query.cc:113 [opt]
    frame #22: C4QueryEnumerator* c4Internal::tryCatch<C4QueryEnumerator*>(C4Error*, fleece::function_ref<C4QueryEnumerator* ()>) [inlined] fleece::function_ref<C4QueryEnumerator* ()>::operator()() const at function_ref.hh:72 [opt]
    frame #23: C4QueryEnumerator* c4Internal::tryCatch<C4QueryEnumerator*>(outError=0x000070000aa4c750, fn=<unavailable>)>) at c4ExceptionUtils.hh:60 [opt]
    frame #24: ::-[CBLQueryResultSet refresh:](NSError **) [inlined] c4queryenum_refresh(outError=0x000000005d160059) at c4Query.cc:239 [opt]
    frame #25: ::-[CBLQueryResultSet refresh:](self=0x00006000526c1f00, _cmd=<unavailable>, outError=0x000070000aa4c798) at CBLQueryResultSet.mm:181 [opt]
    frame #26: ::-[CBLLiveQuery update](self=0x000060005202d680, _cmd=<unavailable>) at CBLLiveQuery.mm:201 [opt]
    frame #27: _dispatch_client_callout + 8
...

Full crash log

snej added a commit to couchbaselabs/fleece that referenced this issue Feb 28, 2019

Added more troubleshooting for Scope, in debug builds
Scope::unregister will throw an exception if the data has changed
since it was registered. This usually means the data was invalidated /
freed, and indicates the Scope needs to be unregistered earlier.

For couchbase/couchbase-lite-core#712

@snej snej closed this in 6a0e37b Feb 28, 2019

@snej

This comment has been minimized.

Copy link
Member Author

commented Feb 28, 2019

This exception happens when two conflicting Scopes are registered on the same region of memory. It happens when a Scope outlives the heap block containing its data — what can happen then is that memory gets allocated for another heap block, and then a new Scope is registered for that block.

I had the idea of having Scope's destructor check whether the contents of the memory range have changed since it was constructed. Since Fleece docs are immutable, this should never happen. But if the heap block was freed, it will be altered immediately (at least in a debug build, thanks to MallocScribble.)

This exposed a bug in some of the internal query code, which I've fixed.
And manual code inspection turned up a smaller bug that I fixed too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.