Check that receiver is not nullptr on Pointer extension methods. (#106)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1f15135..ea60851 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 1.1.1
+
+Adds a sanity check to `Pointer<Utf8>` and `Pointer<Utf16>` extension methods
+that receiver is not `nullptr`.
+
 ## 1.1.0
 
 Adds the `arena` allocator.
diff --git a/lib/src/utf16.dart b/lib/src/utf16.dart
index f5bea5b..25c22ed 100644
--- a/lib/src/utf16.dart
+++ b/lib/src/utf16.dart
@@ -22,12 +22,9 @@
   /// The UTF-16 code units of the strings are the non-zero code units up to
   /// the first zero code unit.
   int get length {
-    final Pointer<Uint16> array = cast<Uint16>();
-    int length = 0;
-    while (array[length] != 0) {
-      length++;
-    }
-    return length;
+    _ensureNotNullptr('length');
+    final codeUnits = cast<Uint16>();
+    return _length(codeUnits);
   }
 
   /// Converts this UTF-16 encoded string to a Dart string.
@@ -38,12 +35,17 @@
   ///
   /// If [length] is provided, zero-termination is ignored and the result can
   /// contain NUL characters.
+  ///
+  /// If [length] is not provided, the returned string is the string up til
+  /// but not including  the first NUL character.
   String toDartString({int? length}) {
+    _ensureNotNullptr('toDartString');
+    final codeUnits = cast<Uint16>();
     if (length == null) {
-      return _toUnknownLengthString(cast<Uint16>());
+      return _toUnknownLengthString(codeUnits);
     } else {
       RangeError.checkNotNegative(length, 'length');
-      return _toKnownLengthString(cast<Uint16>(), length);
+      return _toKnownLengthString(codeUnits, length);
     }
   }
 
@@ -62,6 +64,21 @@
       i++;
     }
   }
+
+  static int _length(Pointer<Uint16> codeUnits) {
+    var length = 0;
+    while (codeUnits[length] != 0) {
+      length++;
+    }
+    return length;
+  }
+
+  void _ensureNotNullptr(String operation) {
+    if (this == nullptr) {
+      throw UnsupportedError(
+          "Operation '$operation' not allowed on a 'nullptr'.");
+    }
+  }
 }
 
 /// Extension method for converting a [String] to a `Pointer<Utf16>`.
diff --git a/lib/src/utf8.dart b/lib/src/utf8.dart
index 04dd7a7..49c1cd3 100644
--- a/lib/src/utf8.dart
+++ b/lib/src/utf8.dart
@@ -22,12 +22,9 @@
   /// The UTF-8 code units of the strings are the non-zero code units up to the
   /// first zero code unit.
   int get length {
-    final Pointer<Uint8> array = cast<Uint8>();
-    int length = 0;
-    while (array[length] != 0) {
-      length++;
-    }
-    return length;
+    _ensureNotNullptr('length');
+    final codeUnits = cast<Uint8>();
+    return _length(codeUnits);
   }
 
   /// Converts this UTF-8 encoded string to a Dart string.
@@ -38,13 +35,33 @@
   ///
   /// If [length] is provided, zero-termination is ignored and the result can
   /// contain NUL characters.
+  ///
+  /// If [length] is not provided, the returned string is the string up til
+  /// but not including  the first NUL character.
   String toDartString({int? length}) {
+    _ensureNotNullptr('toDartString');
+    final codeUnits = cast<Uint8>();
     if (length != null) {
       RangeError.checkNotNegative(length, 'length');
     } else {
-      length = this.length;
+      length = _length(codeUnits);
     }
-    return utf8.decode(cast<Uint8>().asTypedList(length));
+    return utf8.decode(codeUnits.asTypedList(length));
+  }
+
+  static int _length(Pointer<Uint8> codeUnits) {
+    var length = 0;
+    while (codeUnits[length] != 0) {
+      length++;
+    }
+    return length;
+  }
+
+  void _ensureNotNullptr(String operation) {
+    if (this == nullptr) {
+      throw UnsupportedError(
+          "Operation '$operation' not allowed on a 'nullptr'.");
+    }
   }
 }
 
diff --git a/pubspec.yaml b/pubspec.yaml
index 11dd576..89e6180 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: ffi
-version: 1.1.0
+version: 1.1.1
 homepage: https://github.com/dart-lang/ffi
 description: Utilities for working with Foreign Function Interface (FFI) code.
 
diff --git a/test/utf16_test.dart b/test/utf16_test.dart
index 615056a..c962b46 100644
--- a/test/utf16_test.dart
+++ b/test/utf16_test.dart
@@ -60,7 +60,29 @@
   });
 
   test('fromUtf8 with negative length', () {
-    final Pointer<Utf16> utf16 = Pointer.fromAddress(0);
+    final string = 'Hello';
+    final utf16 = string.toNativeUtf16();
     expect(() => utf16.toDartString(length: -1), throwsRangeError);
+    calloc.free(utf16);
+  });
+
+  test('nullptr.toDartString()', () {
+    final Pointer<Utf16> utf16 = nullptr;
+    try {
+      utf16.toDartString();
+    } on UnsupportedError {
+      return;
+    }
+    fail('Expected an error.');
+  });
+
+  test('nullptr.length', () {
+    final Pointer<Utf16> utf16 = nullptr;
+    try {
+      utf16.length;
+    } on UnsupportedError {
+      return;
+    }
+    fail('Expected an error.');
   });
 }
diff --git a/test/utf8_test.dart b/test/utf8_test.dart
index 9c0486a..d3f2fee 100644
--- a/test/utf8_test.dart
+++ b/test/utf8_test.dart
@@ -96,4 +96,24 @@
     expect(utf8Pointer.length, 5);
     calloc.free(utf8Pointer);
   });
+
+  test('nullptr.toDartString()', () {
+    final Pointer<Utf8> utf8 = nullptr;
+    try {
+      utf8.toDartString();
+    } on UnsupportedError {
+      return;
+    }
+    fail('Expected an error.');
+  });
+
+  test('nullptr.length', () {
+    final Pointer<Utf8> utf8 = nullptr;
+    try {
+      utf8.length;
+    } on UnsupportedError {
+      return;
+    }
+    fail('Expected an error.');
+  });
 }