[jnigen] Fix buffer overflow issue when converting strings from JNI to Dart (https://github.com/dart-lang/jnigen/issues/416)

diff --git a/pkgs/jni/CHANGELOG.md b/pkgs/jni/CHANGELOG.md
index e4f919c..2065bb1 100644
--- a/pkgs/jni/CHANGELOG.md
+++ b/pkgs/jni/CHANGELOG.md
@@ -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)).
 
diff --git a/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart
index 2554041..4993aee 100644
--- a/pkgs/jni/lib/src/jni.dart
+++ b/pkgs/jni/lib/src/jni.dart
@@ -330,8 +330,7 @@
 }
 
 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}) {
@@ -342,7 +341,8 @@
     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);
@@ -377,7 +377,7 @@
 
 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);
   }
 }
diff --git a/pkgs/jni/lib/src/lang/jstring.dart b/pkgs/jni/lib/src/lang/jstring.dart
index 9e542ff..9b8fbbb 100644
--- a/pkgs/jni/lib/src/lang/jstring.dart
+++ b/pkgs/jni/lib/src/lang/jstring.dart
@@ -4,7 +4,6 @@
 
 import 'dart:ffi';
 
-import 'package:ffi/ffi.dart';
 import 'package:jni/src/jreference.dart';
 
 import '../jni.dart';
@@ -59,10 +58,7 @@
   /// 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();
     }
diff --git a/pkgs/jni/test/global_env_test.dart b/pkgs/jni/test/global_env_test.dart
index 9b6a8b2..a5588cd 100644
--- a/pkgs/jni/test/global_env_test.dart
+++ b/pkgs/jni/test/global_env_test.dart
@@ -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';
@@ -118,19 +119,32 @@
           }));
 
   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) {
             final system =