Skip to content

EXC_BAD_ACCESS fatal crash on iOS 17 when accessing store from within isolate #654

Open
@JaffaKetchup

Description

@JaffaKetchup

Is there an existing issue?

Build info

  • objectbox version: 4.0
  • Flutter/Dart version: Flutter 3.22
  • Build OS: Uncertain
  • Deployment OS or device: Reported on iOS 17

Steps to reproduce

This report is based on a report to a library I own: JaffaKetchup/flutter_map_tile_caching#159. Therefore, some information is limited as a 3rd party suffered the issue. I am providing as much information as possible, please let me know if more is required.

  1. The issue appears to occur on iOS devices - unfortunately I do not have an iOS device to test
  2. The last breakpoint hit appears to suggest the following code triggers the issue:
Code A
Future<int> deleteTiles({
    required Query<ObjectBoxStore> storesQuery,
    required Query<ObjectBoxTile> tilesQuery,
  }) async {
    final stores = root.box<ObjectBoxStore>();
    final tiles = root.box<ObjectBoxTile>();

    bool hadTilesToUpdate = false;
    int rootDeltaSize = 0;
    final tilesToRemove = <int>[];
    final storesToUpdate = <String, ObjectBoxStore>{};

    final queriedStores = storesQuery.property(ObjectBoxStore_.name).find();
    if (queriedStores.isEmpty) return 0;

    // For each store, remove it from the tile if requested
    // For each store & if removed, update that store's stats
    await for (final tile in tilesQuery.stream()) { // APPEARS TO CRASH HERE
      tile.stores.removeWhere((store) {
        if (!queriedStores.contains(store.name)) return false;

        storesToUpdate[store.name] = (storesToUpdate[store.name] ?? store)
          ..length -= 1
          ..size -= tile.bytes.lengthInBytes;

        return true;
      });

      if (tile.stores.isNotEmpty) {
        tile.stores.applyToDb(mode: PutMode.update);
        hadTilesToUpdate = true;
        continue;
      }

      rootDeltaSize -= tile.bytes.lengthInBytes;
      tilesToRemove.add(tile.id);
    }

    if (!hadTilesToUpdate && tilesToRemove.isEmpty) return 0;

    root.runInTransaction(
      TxMode.write,
      () {
        tilesToRemove.forEach(tiles.remove);

        updateRootStatistics(
          deltaLength: -tilesToRemove.length,
          deltaSize: rootDeltaSize,
        );

        stores.putMany(
          storesToUpdate.values.toList(),
          mode: PutMode.update,
        );
      },
    );

    return tilesToRemove.length;
  }

This code is inside an isolate, and is called also from within the same isolate, with the following arguments:

Code B
// This code is held within a switch statement executed by listening to a `RecievePort`

final String storeName = '<argument>';

final tiles = root.box<ObjectBoxTile>();
final stores = root.box<ObjectBoxStore>();

final storeQuery = stores.query(ObjectBoxStore_.name.equals(storeName)).build();
final store = storeQuery.findUnique() ?? (throw StoreNotExists(storeName: storeName));

final tilesQuery = (tiles.query()
        ..linkMany(
          ObjectBoxTile_.stores,
          ObjectBoxStore_.name.equals(storeName),
        ))
      .build();

deleteTiles(storesQuery: storeQuery, tilesQuery: tilesQuery).then((_) {
	// likely irrelevant, but effectively signals to the 'parent' 'main thread' isolate that the operation is complete
});

This looks similar to #379 (which was also related to usage in isolates), but it may not be. To open the stores in the new isolate, we use the new attach API, not fromReference. Maybe the issue is streaming in an isolate?

If more code is needed, all code is available on the FMTC repo. I can help filter out whatever is needed.

FMTC also uses the term 'store' to mean something different to an ObjectBox Store.

Expected behavior

The provided code should execute successfully, deleting the specified 'tiles' from the specified 'stores'.

Actual behavior

The application fatally crashes with the exception shown in the logs below.

Code

As I cannot reproduce the issue myself, I cannot provide an MRE without flutter_map_tile_caching.

However, the original reporter provided an MRE that uses the flutter_map_tile_caching dependency: JaffaKetchup/flutter_map_tile_caching#159 (comment). It may be that more specific circumstances are required.

I can try to provide more information if possible, but given that I don't think I can reproduce this bug as it is, that's difficult.

The log below is produced on FMTC's example application.

Logs, stack traces

Basic error snippet: DartWorker (177): EXC_BAD_ACCESS (code=1, address=0x12ab68010)
iOS Platform Log: pastebin.com/qQCwULRb
pubspec.lock (please note that this is a reproduction on my machine, not from the original reporter (see below)): pastebin.com/1vejE0p3

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdocumentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions