Make hidl_vec/hidl_string safe for 32<->64 IPC.

Pointers going over IPC always need to be 64-bit.
This change introduces a hidl_pointer class that
wraps a pointer (without taking ownership), and
stuffs it in a union with a uint64_t to ensure we
always have 64-bits.

We can map size_t to either a fixed 32-bit or fixed
64-bit type. Since sending objects of more than
2^32 bytes seems a while out, we can save ourselves
4 bytes by allowing a maximum of 2^32 elements in
hidl_vec, and 2^32 characters in a string.

Bug: 32089785
Test: hidl_test, hidl_string 32->64->32
Change-Id: Ife77f7362013226aada51c7686e33494390824d7
diff --git a/include/hidl/HidlSupport.h b/include/hidl/HidlSupport.h
index 48cfd26..c11d680 100644
--- a/include/hidl/HidlSupport.h
+++ b/include/hidl/HidlSupport.h
@@ -33,6 +33,77 @@
 namespace android {
 namespace hardware {
 
+namespace details {
+
+// hidl_log_base is a base class that templatized
+// classes implemented in a header can inherit from,
+// to avoid creating dependencies on liblog.
+struct hidl_log_base {
+    void logAlwaysFatal(const char *message);
+};
+
+// HIDL client/server code should *NOT* use this class.
+//
+// hidl_pointer wraps a pointer without taking ownership,
+// and stores it in a union with a uint64_t. This ensures
+// that we always have enough space to store a pointer,
+// regardless of whether we're running in a 32-bit or 64-bit
+// process.
+template<typename T>
+struct hidl_pointer {
+    hidl_pointer()
+        : mPointer(nullptr) {
+    }
+    hidl_pointer(T* ptr)
+        : mPointer(ptr) {
+    }
+    hidl_pointer(const hidl_pointer<T>& other) {
+        mPointer = other.mPointer;
+    }
+    hidl_pointer(hidl_pointer<T>&& other) {
+        *this = std::move(other);
+    }
+
+    hidl_pointer &operator=(const hidl_pointer<T>& other) {
+        mPointer = other.mPointer;
+        return *this;
+    }
+    hidl_pointer &operator=(hidl_pointer<T>&& other) {
+        mPointer = other.mPointer;
+        other.mPointer = nullptr;
+        return *this;
+    }
+    hidl_pointer &operator=(T* ptr) {
+        mPointer = ptr;
+        return *this;
+    }
+
+    operator T*() const {
+        return mPointer;
+    }
+    explicit operator void*() const { // requires explicit cast to avoid ambiguity
+        return mPointer;
+    }
+    T& operator*() const {
+        return *mPointer;
+    }
+    T* operator->() const {
+        return mPointer;
+    }
+    T &operator[](size_t index) {
+        return mPointer[index];
+    }
+    const T &operator[](size_t index) const {
+        return mPointer[index];
+    }
+private:
+    union {
+        T* mPointer;
+        uint64_t _pad;
+    };
+};
+} // namespace details
+
 struct hidl_string {
     hidl_string();
     ~hidl_string();
@@ -76,8 +147,8 @@
     static const size_t kOffsetOfBuffer;
 
 private:
-    const char *mBuffer;
-    size_t mSize;  // NOT including the terminating '\0'.
+    details::hidl_pointer<const char> mBuffer;
+    uint32_t mSize;  // NOT including the terminating '\0'.
     bool mOwnsBuffer; // if true then mBuffer is a mutable char *
 
     // copy from data with size. Assume that my memory is freed
@@ -106,7 +177,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 template<typename T>
-struct hidl_vec {
+struct hidl_vec : private details::hidl_log_base {
     hidl_vec()
         : mBuffer(NULL),
           mSize(0),
@@ -152,7 +223,10 @@
             delete [] mBuffer;
         }
         mBuffer = data;
-        mSize = size;
+        if (size > UINT32_MAX) {
+            logAlwaysFatal("external vector size exceeds 2^32 elements.");
+        }
+        mSize = static_cast<uint32_t>(size);
         mOwnsBuffer = shouldOwn;
     }
 
@@ -225,9 +299,12 @@
     }
 
     void resize(size_t size) {
+        if (size > UINT32_MAX) {
+            logAlwaysFatal("hidl_vec can't hold more than 2^32 elements.");
+        }
         T *newBuffer = new T[size];
 
-        for (size_t i = 0; i < std::min(size, mSize); ++i) {
+        for (size_t i = 0; i < std::min(static_cast<uint32_t>(size), mSize); ++i) {
             newBuffer[i] = mBuffer[i];
         }
 
@@ -236,15 +313,15 @@
         }
         mBuffer = newBuffer;
 
-        mSize = size;
+        mSize = static_cast<uint32_t>(size);
         mOwnsBuffer = true;
     }
 
     // offsetof(hidl_string, mBuffer) exposed since mBuffer is private.
     static const size_t kOffsetOfBuffer;
 private:
-    T *mBuffer;
-    size_t mSize;
+    details::hidl_pointer<T> mBuffer;
+    uint32_t mSize;
     bool mOwnsBuffer;
 
     // copy from an array-like object, assuming my resources are freed.