objectbox-dart
objectbox-dart copied to clipboard
iOS Query Builder Crash
Description
App is crashing when trying to build a Boolean query condition on iOS. The crash happens on the the C/C++ layer so I couldn't investigate more.
According to this comment on another thread the method obx_dart_query_find_ptr was supposed to be of internal usage only?
Could you help? This is affecting a portion of our crash free user rate and damaging the company reputation.
Is there an existing issue?
- [X] I have searched existing issues
Build info
- objectbox version: 4.0.3
- Flutter/Dart version: 3.27.3
- Build OS: macOS
- Deployment OS or device: iOS 18.3.2
Steps to reproduce
I couldn't reproduce this issue myself but it is happening on a portion of our production users.
Expected behavior
To not crash when building query condition
Actual behavior
App crashes
Code
Code
Entity
import 'package:objectbox/objectbox.dart';
@Entity()
class TemplateSectionObx {
TemplateSectionObx({
this.id = 0,
required this.templateId,
this.isNew = false,
this.hasSynced = true,
this.alwaysPageBreak = false,
this.disclaimerText,
this.icon,
this.identifier,
this.isDefault = false,
this.isOverview = false,
this.lockItemAdding = false,
this.locked = false,
this.name,
this.notes = '',
this.priority = 0,
this.qualityScoreMultiplier,
this.createdAt,
this.updatedAt,
this.deletedAt,
});
@Id(assignable: true)
int id;
@Index()
final int templateId;
@Index()
final bool hasSynced;
final bool isNew;
final bool alwaysPageBreak;
final String? disclaimerText;
final String? icon;
final String? identifier;
final bool isDefault;
final bool isOverview;
final bool lockItemAdding;
final bool locked;
final String? name;
final String notes;
final int priority;
final int? qualityScoreMultiplier;
@Property(type: PropertyType.date)
final DateTime? createdAt;
@Property(type: PropertyType.date)
final DateTime? updatedAt;
final String? deletedAt;
}
Failing Query
final query = box.query(TemplateSectionObx_.hasSynced.equals(false)).build();
final results = query.find();
query.close();
objectbox: ^4.0.3
objectbox_flutter_libs: any
...
objectbox_generator: any
Logs, stack traces
Logs
ObjectBox deps
├── objectbox 4.0.3
│ ├── flat_buffers 23.5.26
│ ├── collection...
│ ├── ffi...
│ ├── meta...
│ └── path...
├── objectbox_flutter_libs 4.0.3
│ ├── flutter...
│ ├── objectbox...
│ └── path_provider...
├── objectbox_generator 4.0.3
│ ├── analyzer...
│ ├── build...
│ ├── collection...
│ ├── dart_style...
│ ├── glob...
│ ├── http...
│ ├── objectbox...
│ ├── path...
│ ├── pointycastle...
│ ├── pubspec_parse...
│ ├── source_gen...
│ └── yaml...
Crash
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000020
Exception Codes: 0x0000000000000001, 0x0000000000000020
VM Region Info: 0x20 is not in any region. Bytes before following region: 4332404704
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
__TEXT 1023b4000-1023bc000 [ 32K] r-x/r-x SM=COW /var/containers/Bundle/Application/CF850A06-4A29-40CB-AA6E-CF6F7E23BE93/Runner.app/Runner
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [14185]
Triggered by Thread: 19
Thread
Thread 19 Crashed:
0 ObjectBox 0x00000001043d50c0 obx_dart_query_find_ptr + 589584
1 ObjectBox 0x0000000104329028 obx_qb_equals_int + 76
2 App 0x000000011254d53c stub CallNativeThroughSafepoint + 88
3 App 0x00000001128553c0 ObjectBoxC._qb_order.#ffiClosure231 + 116 (objectbox_c.dart:4938)
4 App 0x0000000112ed3d1c ObjectBoxC.qb_equals_int (#2) + 100 (objectbox_c.dart:4378)
5 App 0x0000000112ed3c90 ObjectBoxC.qb_equals_int + 44 (objectbox_c.dart:4373)
6 App 0x0000000112ed33d0 IntegerCondition._op1 + 96 (query.dart:680)
7 App 0x0000000112ed2e70 IntegerCondition._apply + 156 (query.dart:686)
8 App 0x00000001127d58ac Condition._applyFull + 56 (query.dart:537)
9 App 0x00000001127d4a24 _QueryBuilder._applyCondition + 56 (builder.dart:146)
10 App 0x00000001127d4a24 QueryBuilder.build + 56 (builder.dart:17)
11 App 0x0000000112860424 fetchUnsynced (#3) + 196 (template_section_plugin.dart:200)
12 App 0x0000000112860348 registerTemplateSectionObxPlugin.<anonymous closure> (#3) + 48 (template_section_plugin.dart:81)
13 App 0x0000000112852090 runWithErrorRecovery + 252 (isolate_manager.dart:249)
14 App 0x000000011285ed40 registerTemplateSectionObxPlugin + 1212 (template_section_plugin.dart:77)
15 App 0x0000000112851ca8 isolateEntryPoint.<anonymous closure> + 848 (isolate_manager.dart:365)
16 App 0x0000000112dc2d88 RootZone.runUnaryGuarded + 124 (zone.dart:1609)
17 App 0x0000000112d458b4 BufferingStreamSubscription._sendData + 196 (stream_impl.dart:366)
18 App 0x0000000112d1f34c BufferingStreamSubscription._add (#3) + 136 (stream_impl.dart:297)
19 App 0x0000000112d1f24c _SyncStreamControllerDispatch._sendData + 24 (stream_controller.dart:777)
20 App 0x0000000112d1f24c StreamController._add (#3) + 188 (stream_controller.dart:651)
21 App 0x00000001125ffaa0 StreamController.add (#3) + 104 (stream_controller.dart:606)
22 App 0x0000000112579dd0 StreamController.add (#2) + 36
23 App 0x0000000112f31110 Closure.call (#2) + 704 (function.dart:0)
24 App 0x00000001125ee914 RawReceivePort._handleMessage + 184 (isolate_patch.dart:184)
25 App 0x000000011254fb8c stub InvokeDartCode + 216
26 Flutter 0x0000000106c7804c dart::InvokeDartCode(unsigned long, dart::Array const&, dart::Array const&, dart::Thread*) + 328 (dart_entry.cc:106)
27 Flutter 0x0000000106c7804c dart::DartEntry::InvokeFunction(dart::Function const&, dart::Array const&, dart::Array const&) + 384 (dart_entry.cc:149)
28 Flutter 0x0000000106c83d8c dart::DartEntry::InvokeFunction(dart::Function const&, dart::Array const&) + 76 (dart_entry.cc:38)
29 Flutter 0x0000000106c83d8c dart::DartLibraryCalls::HandleMessage(long long, dart::Instance const&) + 168 (dart_entry.cc:718)
30 Flutter 0x0000000106c83d8c dart::IsolateMessageHandler::HandleMessage(std::_fl::unique_ptr<dart::Message, std::_fl::default_delete<dart::Message>>) + 2772 (isolate.cc:1456)
31 Flutter 0x0000000106c88d04 dart::MessageHandler::HandleMessages(dart::MonitorLocker*, bool, bool) + 324 (message_handler.cc:229)
32 Flutter 0x0000000106c88b4c dart::MessageHandler::TaskCallback() + 116 (message_handler.cc:443)
33 Flutter 0x0000000106c88b4c dart::MessageHandlerTask::Run() + 140 (message_handler.cc:31)
34 Flutter 0x0000000106d222ec dart::ThreadPool::WorkerLoop(dart::ThreadPool::Worker*) + 168 (thread_pool.cc:203)
35 Flutter 0x0000000106d222ec dart::ThreadPool::Worker::Main(unsigned long) + 376 (thread_pool.cc:363)
36 Flutter 0x0000000106ce590c dart::ThreadStart(void*) + 312 (os_thread_macos.cc:94)
37 libsystem_pthread.dylib 0x0000000227bc27d0 _pthread_start + 136 (pthread.c:931)
38 libsystem_pthread.dylib 0x0000000227bc2480 thread_start + 8 (:-1)
Thanks for reporting.
As I noted in the other issue, the symbolicated stack trace is likely not correct for the ObjectBox lines.
First, I recommend to make sure that your project can upgrade to the latest ObjectBox Dart packages (yours appears to be stuck on 4.0.3, the latest available version is 4.2.0, dart pub updated could help) and ObjectBox Pod. And also using the latest Flutter SDK (and therefore the latest Dart SDK) may help.
But thanks for sharing the crash log, at least we now know this is happening during building a query.
Do you see any pattern on which devices are affected, like model, iOS version?
Edit: for our reference, this is internal issue objectbox-dart#146
Mostly iPhones
Testflight
Production
Another quick note is that we have other similar entities such as TemplateItem and TemplateComment where we do similar querying hasSynced but it seems like it is only affecting the TemplateSection entity
@GabrielAraujo Thanks! In that case, can you share more about where the query builder code is used (maybe also compared to the other entities)? The log shows StreamController and hints at the use of isolates?
There have been similar issues to this which I think are rooted in the fact that the ObjectBox database is a native component that exists outside of all Dart isolates. Somehow the database gets closed, then causing a crash when trying to use it from Dart.
So those queries run every 30 seconds or so to fetch locally models that haven't synced yet to the remote servers. Once the changes sync we update the models locally setting this hasSynced attribute to true.
We've recently ported most of our sync operations with lists and async operations from ObjectBox to sync ones inside a single isolate worker. The same store is used on the main isolate and on this background isolate worker.
This isolate is spawned at app startup and only closes when app is closed.
Not related Note: We've done this migration because we were having some overhead with isolate spawn when using async objectbox operations directly and in some use cases using the sync one with large lists were causing UI jank.
The 4.3.1 release shipped with database libraries that have improved code to wait on database operations like queries before closing a Store. This should avoid the crash observed in this issue (EXC_BAD_ACCESS (SIGSEGV)).
Note: I labeled this issue with "more info required" so it will auto-close in a few days if there are no follow-up comments.
Note that there are similar issues: #626, #654 and maybe some others.