dart-lang / native

Dart packages related to FFI and native assets bundling.
BSD 3-Clause "New" or "Revised" License
155 stars 43 forks source link

"Dart Error: Internal Dart data pointers have been acquired, please release them using Dart_TypedDataReleaseData." #898

Open drriguz opened 3 years ago

drriguz commented 3 years ago

Hi there,

I'm using dart:ffi on flutter to use sqlite from c code. However, I got a strange error:

[VERBOSE-2:shell.cc(210)] Dart Error: Internal Dart data pointers have been acquired, please release them using Dart_TypedDataReleaseData.
Lost connection to device.

I guess it's because some raw bytes are allocated but not released, however I've no idea how to fix this, Dart_TypedDataReleaseData seems to be some dart VM function.

Related code

Here is the code I suspect that causes the problem:

  Uint8List readColumnByIndexAsBytes(int columnIndex) {
    _checkIsCurrentRow();
    int length = bindings.sqlite3_column_bytes(_statement, columnIndex);
    Pointer<Uint8> buffer =
        bindings.sqlite3_column_blob(_statement, columnIndex);
    return buffer.asTypedList(length);
  }

Frameworks

Flutter (Channel beta, 1.23.0-18.1.pre, on Mac OS X 10.15.4 19E287 x86_64, locale en-CN) Dart SDK version: 2.11.0-213.1.beta (beta) (Wed Oct 14 10:49:52 2020 +0200) on "macos_x64"

Thanks!

mkustermann commented 3 years ago

/cc @dcharkes

dcharkes commented 3 years ago

Hi @drriguz

Thanks for filing this issue. This is indeed an error message from inside the DartVM.

Could you please provide the source code for a minimal example for reproducing this? (Dart standalone, or Flutter.) That would help us with tracking down the issue.

drriguz commented 3 years ago

Thanks, guys, I'll try to create a minimal project to reproduce this, I'll let you know once I finished.

drriguz commented 3 years ago

@dcharkes Hi, I figured out the reason, here is a simple piece of flutter code to reproduce it:

Reproduce

import 'dart:ffi';
import 'dart:typed_data';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  Widget _item(int index) {
    Pointer<Uint8> p = Pointer.fromAddress(0);
    Uint8List empty = p.asTypedList(0);
    return Image.memory(empty, width: 48, height: 48);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: ListView.builder(
          itemCount: 1,
          itemBuilder: (_, index) => _item(index),
        ),
      ),
    );
  }
}

Running this will get lots of error:

Launching lib/main.dart on iPhone SE (2nd generation) in debug mode...
Running Xcode build...
Xcode build done.                                           22.9s
Waiting for iPhone SE (2nd generation) to report its views...
Debug service listening on ws://127.0.0.1:64872/b2WiYaSfP8k=/ws
Syncing files to device iPhone SE (2nd generation)...
[VERBOSE-2:shell.cc(210)] Dart Error: Internal Dart data pointers have been acquired, please release them using Dart_TypedDataReleaseData.
[VERBOSE-2:shell.cc(210)] Dart Error: Internal Dart data pointers have been acquired, please release them using Dart_TypedDataReleaseData.
...

It's quite interesting that, somehow Image.memory with a empty pointer will cause such an issue.

Pointer<Uint8> p = Pointer.fromAddress(0);
Uint8List empty = p.asTypedList(0);
return Image.memory(empty, width: 48, height: 48);

My original cause is that, I'm trying to read a null column,

 Uint8List readColumnByIndexAsBytes(int columnIndex) {
    _checkIsCurrentRow();
    int length = bindings.sqlite3_column_bytes(_statement, columnIndex);

    // if the column is empty, then sqlite3_column_blob will return a nullptr
    Pointer<Uint8> buffer = bindings.sqlite3_column_blob(_statement, columnIndex);
    return buffer.asTypedList(length);
}

I'm curious about the root cause of that, but I'm not sure whether we could do some thing to avoid that(or get better error message) , thanks!

dcharkes commented 3 years ago

In general, passing invalid pointers to asTypedList, or anything else that expects valid pointers, causes undefined behavior. I could go and investigate what specifically goes wrong in the VM/Flutter here, but if you are able to prevent calling asTypedList with invalid pointers in your code, you should be unblocked to work on your project.

drriguz commented 3 years ago

yes, exactly. thanks!

mkustermann commented 3 years ago

@dcharkes This is an indication of an actual bug. Using a 0-length external typed data with any address should be fine.