objectbox-dart icon indicating copy to clipboard operation
objectbox-dart copied to clipboard

iOS Query Builder Crash

Open GabrielAraujo opened this issue 6 months ago • 4 comments
trafficstars

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?

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)

GabrielAraujo avatar Apr 25 '25 15:04 GabrielAraujo

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

greenrobot-team avatar Apr 28 '25 06:04 greenrobot-team

Mostly iPhones

Testflight Image

Production Image

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 avatar Apr 28 '25 18:04 GabrielAraujo

@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.

greenrobot-team avatar Apr 29 '25 04:04 greenrobot-team

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.

GabrielAraujo avatar Apr 29 '25 14:04 GabrielAraujo

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.

greenrobot-team avatar Sep 09 '25 07:09 greenrobot-team