Skip to content

Low level error upon QueryBuilder.watch(triggerImmediaterly: true) #343

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

Closed
h7x4 opened this issue Dec 2, 2021 · 6 comments
Closed

Low level error upon QueryBuilder.watch(triggerImmediaterly: true) #343

h7x4 opened this issue Dec 2, 2021 · 6 comments
Labels
question How to do something/general question

Comments

@h7x4
Copy link

h7x4 commented Dec 2, 2021

Parts of the native library produces a low level error upon executing queryBuilder.watch(triggerImmediately: true).

Basic info:

  • ObjectBox version: ^1.3.0
$ flutter --version
Flutter 2.5.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 18116933e7 (7 weeks ago) • 2021-10-15 10:46:35 -0700
Engine • revision d3ea636dc5
Tools • Dart 2.14.4
  • Null-safety enabled: yes
  • Reproducibility: always
  • OS: Linux 5.10.79-1-MANJARO
  • Device/Emulator: Pixel 3 API 30 (emulator) and Samsung S8 Plus (SM-G855F) API 28
flutter deps --no-dev
Dart SDK 2.14.4
Flutter SDK 2.5.3
example_ob_app 1.0.0+1
|-- flutter 0.0.0
|   |-- characters 1.1.0
|   |-- collection 1.15.0
|   |-- meta 1.7.0
|   |-- sky_engine 0.0.99
|   |-- typed_data 1.3.0
|   |   '-- collection...
|   '-- vector_math 2.1.0
|-- objectbox 1.3.0
|   |-- collection...
|   |-- ffi 1.1.2
|   |-- meta...
|   '-- path 1.8.0
'-- objectbox_flutter_libs 1.3.0
    |-- objectbox...
    '-- path_provider 2.0.7
        |-- flutter...
        |-- path_provider_android 2.0.9
        |   |-- flutter...
        |   '-- path_provider_platform_interface...
        |-- path_provider_ios 2.0.7
        |   |-- flutter...
        |   '-- path_provider_platform_interface...
        |-- path_provider_linux 2.1.2
        |   |-- flutter...
        |   |-- path...
        |   |-- path_provider_platform_interface...
        |   '-- xdg_directories 0.2.0
        |       |-- meta...
        |       |-- path...
        |       '-- process 4.2.4
        |           |-- file 6.1.2
        |           |   |-- meta...
        |           |   '-- path...
        |           |-- path...
        |           '-- platform...
        |-- path_provider_macos 2.0.3
        |   '-- flutter...
        |-- path_provider_platform_interface 2.0.1
        |   |-- flutter...
        |   |-- meta...
        |   |-- platform 3.0.2
        |   '-- plugin_platform_interface 2.0.2
        |       '-- meta...
        '-- path_provider_windows 2.0.4
            |-- ffi...
            |-- flutter...
            |-- meta...
            |-- path...
            |-- path_provider_platform_interface...
            '-- win32 2.3.1
                '-- ffi...
flutter doctor -v
[✓] Flutter (Channel stable, 2.5.3, on Manjaro Linux 5.10.79-1-MANJARO, locale en_US.utf8)
    • Flutter version 2.5.3 at /opt/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 18116933e7 (7 weeks ago), 2021-10-15 10:46:35 -0700
    • Engine revision d3ea636dc5
    • Dart version 2.14.4

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /home/h7x4/Android/Sdk
    • Platform android-31, build-tools 30.0.2
    • Java binary at: /opt/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)
    • All Android licenses accepted.

[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Android Studio (version 2020.3)
    • Android Studio at /opt/android-studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.10+0-b96-7249189)

[✓] Connected device (2 available)
    • SM G955F (mobile)       • 988a1b383735513546 • android-arm64 • Android 9 (API 28)
    • sdk gphone x86 (mobile) • emulator-5554      • android-x86   • Android 11 (API 30) (emulator)

! Doctor found issues in 1 category.

Steps to reproduce

  • Make a new project:
flutter create example_ob_app
  • Replace main.dart and pubspec.yaml with the code below.

  • Connect a phone/emulator and run the app:

flutter run

Expected behavior

I expected this stream

  Stream<List<Search>> get searchStream {
    final QueryBuilder<Search> queryBuilder = store.box<Search>().query();

    return queryBuilder
        .watch(triggerImmediately: true)
        .map((query) => query.find());
  }

to be a stream that would yield a list of the contents of box<Search>. This would yield a new list every time the contents were updated.

Unfortunately, the code crashes at the return statement. See the debugPrints in the embedded main.dart and the debug console output.

Code

pubspec.yaml
name: example_ob_app
description: A new Flutter project.
publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ">=2.14.4 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  objectbox: ^1.3.0
  objectbox_flutter_libs: ^1.3.0

dev_dependencies:
  build_runner: ^2.0.0
  objectbox_generator: ^1.3.0

flutter:
  uses-material-design: true
main.dart
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:objectbox/objectbox.dart';
import 'package:path_provider/path_provider.dart';

import 'objectbox.g.dart';

@Entity()
class Search {
  int id;

  final String searchTerm;

  Search({
    this.id = 0,
    required this.searchTerm,
  });
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final Directory appDocDir = await getApplicationDocumentsDirectory();

  if (!appDocDir.existsSync()) {
    appDocDir.createSync(recursive: true);
  }

  final Store store = Store(
    getObjectBoxModel(),
    directory: appDocDir.path + '/objectbox',
  );

  debugPrint('Database path: ${appDocDir.path}/objectbox');

  if (store.box<Search>().isEmpty()) {
    store.box<Search>().putMany([
      Search(searchTerm: "Hello"),
      Search(searchTerm: "World"),
    ]);
  }

  runApp(MyApp(store: store));
}

class MyApp extends StatelessWidget {
  final Store store;

  const MyApp({required this.store, Key? key}) : super(key: key);

  Stream<List<Search>> get searchStream {
    debugPrint('Creating queryBuilder');
    final QueryBuilder<Search> queryBuilder = store.box<Search>().query();

    debugPrint('Items: ' +
        queryBuilder
            .build()
            .find()
            .map((e) => e.searchTerm)
            .toList()
            .toString());

    debugPrint('Creating stream');

    return queryBuilder
        .watch(triggerImmediately: true)
        .map((query) => query.find());
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: StreamBuilder<List<Search>>(
        stream: searchStream,
        builder: (BuildContext context, AsyncSnapshot<List<Search>> snapshot) {
          if (!snapshot.hasData) return Container();
          return ListView(
            children: snapshot.data!.map((s) => Text(s.searchTerm)).toList(),
          );
        },
      ),
    );
  }
}

Logs, stack traces

VSCode Debug Console Output
Launching lib/main.dart on sdk gphone x86 in debug mode...
lib/main.dart:1
✓  Built build/app/outputs/flutter-apk/app-debug.apk.
Connecting to VM Service at ws://127.0.0.1:43273/9H9vZUEs6Tc=/ws
I/flutter ( 5501): Database path: /data/user/0/com.example.example_ob_app/app_flutter/objectbox
I/flutter ( 5501): Creating queryBuilder
I/flutter ( 5501): Items: [Hello, World]
I/flutter ( 5501): Creating stream
F/libc    ( 5501): Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xf38 in tid 5558 (1.ui), pid 5501 (.example_ob_app)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sdk_gphone_x86/generic_x86_arm:11/RPB1.200504.020/6557529:user/release-keys'
Revision: '0'
ABI: 'x86'
Timestamp: 2021-12-02 19:42:02+0100
pid: 5501, tid: 5558, name: 1.ui  >>> com.example.example_ob_app <<<
uid: 10150
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xf38
Cause: null pointer dereference
    eax e9000000  ebx acae9b44  ecx 17000f38  edx 00000000
    edi 05c003ce  esi e593c000
    ebp bb3fe238  esp bb3fe1c0  eip ac9d80c4
backtrace:
      #00 pc 000b70c4  /data/app/~~n8k37khzefORQM3GlAvBQg==/com.example.example_ob_app-gPRKGqSg8zpXpu8zpwiGYQ==/base.apk!libobjectbox-jni.so (offset 0x11a9000) (BuildId: b72c90af453b1dd340eb6bb6ee63fd3a19a87e5a)
      #01 pc 000b7dc2  /data/app/~~n8k37khzefORQM3GlAvBQg==/com.example.example_ob_app-gPRKGqSg8zpXpu8zpwiGYQ==/base.apk!libobjectbox-jni.so (offset 0x11a9000) (BuildId: b72c90af453b1dd340eb6bb6ee63fd3a19a87e5a)
      #02 pc 0005906c  /data/app/~~n8k37khzefORQM3GlAvBQg==/com.example.example_ob_app-gPRKGqSg8zpXpu8zpwiGYQ==/base.apk!libobjectbox-jni.so (offset 0x11a9000) (obx_query+76) (BuildId: b72c90af453b1dd340eb6bb6ee63fd3a19a87e5a)
      #03 pc 000041c7  <anonymous:b7d00000>
Lost connection to device.
Exited (sigterm)

(The output for the Samsung device is virtually the same)

Additional context

This is a (somewhat) minimal example extracted from a larger app. I was working on the larger app at around August 2021, and at that time the code worked properly. I might be wrong, but I'm pretty sure this is a bug that has been introduced since that time.

I found an issue with the same segfault code in this project #191, but the person seemed to be using a completely different library with a similar name. However, the question that was answered over there might have similarities to this?

@h7x4 h7x4 added the bug Something isn't working label Dec 2, 2021
@greenrobot-team
Copy link
Member

greenrobot-team commented Dec 6, 2021

Can you try to create a new QueryBuilder for the watch? I suspect this crashes because the QueryBuilder can not be reused once build() was called on it.

So replace above with something like:

    return store.box<Search>().query().
        .watch(triggerImmediately: true)
        .map((query) => query.find());

We should check why there is no proper error message that the builder is already closed.

@h7x4
Copy link
Author

h7x4 commented Dec 9, 2021

I did indeed work with the fix above. I guess marking it as final and putting debugPrints inbetween made flutter optimize it out as some kind of constant-ish value (placing them right beside each other works, even with the queryBuilder marked as final)

@greenrobot
Copy link
Member

So, we should handle this error more gracefully, I guess? @greenrobot-team

@greenrobot-team
Copy link
Member

@h7x4ABk3g This has nothing to do with Flutter optimization. I'll annotate your code, maybe that makes it more clear:

    debugPrint('Creating queryBuilder');
    final QueryBuilder<Search> queryBuilder = store.box<Search>().query();

    debugPrint('Items: ' +
        queryBuilder
            .build() // <-- This builds a Query and closes the QueryBuilder.
            .find()
            .map((e) => e.searchTerm)
            .toList()
            .toString());

    debugPrint('Creating stream');

    return queryBuilder
        .watch(triggerImmediately: true) // <-- tries to reuse already closed QueryBuilder
        .map((query) => query.find());

Or put differently: you can re-use a Query (what is returned by build()), but not QueryBuilder.

@h7x4
Copy link
Author

h7x4 commented Dec 13, 2021

Thank you, I didn't notice! That makes a lot of sense.

@greenrobot-team greenrobot-team added question How to do something/general question and removed bug Something isn't working labels Dec 20, 2021
@greenrobot-team
Copy link
Member

Alright, closing this then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question How to do something/general question
Projects
None yet
Development

No branches or pull requests

3 participants