Detect over/under-flow in UnsizedArray::operator[]

Was causing bad substitutions in mort table because of WordOffsetToIndex()
producing negative numbers that were cast to unsigned int and returned as
large numbers (which was desirable, so they would be rejected), but then
they were cast to int when passed to this operator and acting as small
negative integers, which was bad...

Detect overflow.  Ouch, however, now I see this still fails on 32-bit.
Guess I'm going to revert an earlier change.
diff --git a/src/hb-open-type.hh b/src/hb-open-type.hh
index a14d0f0..bae73da 100644
--- a/src/hb-open-type.hh
+++ b/src/hb-open-type.hh
@@ -339,16 +339,27 @@
 
   HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
 
-  /* Unlikely other places, use "int i" instead of "unsigned int i" for our
-   * indexing operator.  For two reasons:
+  /* Unlikely other places, use "ssize_t i" instead of "unsigned int i" for our
+   * indexing operator.  For three reasons:
    * 1. For UnsizedArrayOf, it's not totally unimaginable to want to look
    *    at items before the start of current array.
-   * 2. Fixes MSVC 2008 "overloads have similar conversions" issue with the
+   * 2. Use the largest type, to help detect overflows.
+   * 3. Fixes MSVC 2008 "overloads have similar conversions" issue with the
    *    built-in operator [] that takes int, in expressions like sizeof (array[0])).
    *    I suppose I could fix that by replacing 0 with 0u, but like this fix
    *    more now. */
-  inline const Type& operator [] (int i) const { return arrayZ[i]; }
-  inline Type& operator [] (int i) { return arrayZ[i]; }
+  inline const Type& operator [] (ssize_t i) const
+  {
+    const Type *p = &arrayZ[i];
+    if (unlikely ((0 <= i) != (arrayZ <= p))) return Null (Type); /* Over/under-flowed. */
+    return *p;
+  }
+  inline Type& operator [] (ssize_t i)
+  {
+    const Type *p = &arrayZ[i];
+    if (unlikely ((0 <= i) != (arrayZ <= p))) return Crap (Type); /* Over/under-flowed. */
+    return *p;
+  }
 
   template <typename T> inline operator T * (void) { return arrayZ; }
   template <typename T> inline operator const T * (void) const { return arrayZ; }