Skip to content

Commit

Permalink
[jnigen] Fix buffer overflow issue when converting strings from JNI t…
Browse files Browse the repository at this point in the history
  • Loading branch information
slightfoot authored Nov 3, 2023
1 parent b4a59e2 commit 69c3e21
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 13 deletions.
3 changes: 3 additions & 0 deletions pkgs/jni/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
- **Breaking Change**: `JArray.filled` now uses the generated type class of the
`fill` object and not its Java runtime type.

## 0.7.2
- Fixed a bug where reading non-null terminated strings would overflow.

## 0.7.1
- Removed macOS Flutter plugin until package:jni supports it ([#41](https://github.com/dart-lang/jnigen/issues/41)).

Expand Down
10 changes: 5 additions & 5 deletions pkgs/jni/lib/src/jni.dart
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,7 @@ extension ProtectedJniExtensions on Jni {
}

extension AdditionalEnvMethods on GlobalJniEnv {
/// Convenience method for converting a [JStringPtr]
/// to dart string.
/// Convenience method for converting a [JStringPtr] to dart string.
/// if [releaseOriginal] is specified, jstring passed will be deleted using
/// DeleteGlobalRef.
String toDartString(JStringPtr jstringPtr, {bool releaseOriginal = false}) {
Expand All @@ -342,7 +341,8 @@ extension AdditionalEnvMethods on GlobalJniEnv {
if (chars == nullptr) {
throw ArgumentError('Not a valid jstring pointer.');
}
final result = chars.cast<Utf16>().toDartString();
final length = GetStringLength(jstringPtr);
final result = chars.cast<Utf16>().toDartString(length: length);
ReleaseStringChars(jstringPtr, chars);
if (releaseOriginal) {
DeleteGlobalRef(jstringPtr);
Expand Down Expand Up @@ -377,7 +377,7 @@ extension StringMethodsForJni on String {

extension CharPtrMethodsForJni on Pointer<Char> {
/// Same as calling `cast<Utf8>` followed by `toDartString`.
String toDartString() {
return cast<Utf8>().toDartString();
String toDartString({int? length}) {
return cast<Utf8>().toDartString(length: length);
}
}
6 changes: 1 addition & 5 deletions pkgs/jni/lib/src/lang/jstring.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:jni/src/jreference.dart';

import '../jni.dart';
Expand Down Expand Up @@ -59,10 +58,7 @@ class JString extends JObject {
/// after conversion and this object will be marked as released.
String toDartString({bool releaseOriginal = false}) {
ensureNotNull();
final length = Jni.env.GetStringLength(reference);
final chars = Jni.env.GetStringChars(reference, nullptr);
final result = chars.cast<Utf16>().toDartString(length: length);
Jni.env.ReleaseStringChars(reference, chars);
final result = Jni.env.toDartString(reference);
if (releaseOriginal) {
release();
}
Expand Down
20 changes: 17 additions & 3 deletions pkgs/jni/test/global_env_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:io';

import 'package:ffi/ffi.dart';
import 'package:jni/jni.dart';
import 'package:jni/src/jvalues.dart';
import 'package:test/test.dart';
Expand Down Expand Up @@ -118,18 +119,31 @@ void run({required TestRunnerCallback testRunner}) {
}));

testRunner(
"Convert back & forth between Dart & Java strings",
"Convert back & forth between Dart & Java strings (UTF-8)",
() => using((arena) {
const str = "ABCD EFGH";
// This is what asJString and asDartString do internally
final jstr = env.NewStringUTF(str.toNativeChars(arena));
final jchars = env.GetStringUTFChars(jstr, nullptr);
final dstr = jchars.toDartString();
final jlen = env.GetStringUTFLength(jstr);
final dstr = jchars.toDartString(length: jlen);
env.ReleaseStringUTFChars(jstr, jchars);
expect(str, equals(dstr));
env.DeleteGlobalRef(jstr);
}));

testRunner(
"Convert back & forth between Dart & Java strings (UTF-16)",
() => using((arena) {
const str = "ABCD EFGH";
final jstr = env.NewString(str.toNativeUtf16().cast(), str.length);
final jchars = env.GetStringChars(jstr, nullptr);
final jlen = env.GetStringLength(jstr);
final dstr = jchars.cast<Utf16>().toDartString(length: jlen);
env.ReleaseStringChars(jstr, jchars);
expect(str, equals(dstr));
env.DeleteGlobalRef(jstr);
}));

testRunner(
"Print something from Java",
() => using((arena) {
Expand Down

0 comments on commit 69c3e21

Please sign in to comment.