Provide an escape hatch for structs in Data Partition

As encountered in
  https://pdfium-review.googlesource.com/c/pdfium/+/98291

Change-Id: Ic427364f7d1f17241e39df429bd8cf2f4db1d915
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/98310
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/fx_memory_wrappers.h b/core/fxcrt/fx_memory_wrappers.h
index 23a5b47..de8042c 100644
--- a/core/fxcrt/fx_memory_wrappers.h
+++ b/core/fxcrt/fx_memory_wrappers.h
@@ -16,6 +16,17 @@
   inline void operator()(void* ptr) const { FX_Free(ptr); }
 };
 
+// Escape hatch mechanism to allow non_arithmetic types into data partition.
+template <typename T>
+struct IsFXDataPartitionException : std::false_type {};
+
+// Use with caution. No further checks are made to see if `T` is appropriate
+// for the Data Partition (e.g. no pointers, strings, vtables, etc.). This
+// declaration must occur in the top-level namespace.
+#define FX_DATA_PARTITION_EXCEPTION(T) \
+  template <>                          \
+  struct IsFXDataPartitionException<T> : std::true_type {}
+
 // Allocators for mapping STL containers onto Partition Alloc.
 // Otherwise, replacing e.g. the FX_AllocUninit/FX_Free pairs with STL may
 // undo some of the nice segregation that we get from PartitionAlloc.
@@ -23,7 +34,8 @@
 struct FxPartitionAllocAllocator {
  public:
 #if !defined(COMPILER_MSVC) || defined(NDEBUG)
-  static_assert(std::is_arithmetic<T>::value,
+  static_assert(std::is_arithmetic<T>::value ||
+                    IsFXDataPartitionException<T>::value,
                 "Only numeric types allowed in this partition");
 #endif
 
@@ -77,7 +89,8 @@
 // Used to put backing store for std::vector<> and such into the
 // general partition, ensuring they contain data only.
 template <typename T,
-          typename = std::enable_if_t<std::is_arithmetic<T>::value, T>>
+          typename = std::enable_if_t<std::is_arithmetic<T>::value ||
+                                      IsFXDataPartitionException<T>::value>>
 using FxAllocAllocator =
     FxPartitionAllocAllocator<T, pdfium::internal::AllocOrDie>;
 
diff --git a/core/fxcrt/fx_memory_wrappers_unittest.cpp b/core/fxcrt/fx_memory_wrappers_unittest.cpp
index f9bee32..5476125 100644
--- a/core/fxcrt/fx_memory_wrappers_unittest.cpp
+++ b/core/fxcrt/fx_memory_wrappers_unittest.cpp
@@ -12,6 +12,17 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+struct OnlyNumbers {
+  int x;
+  int y;
+};
+
+}  // namespace
+
+FX_DATA_PARTITION_EXCEPTION(OnlyNumbers);
+
 TEST(fxcrt, FxFreeDeleter) {
   std::unique_ptr<int, FxFreeDeleter> empty(nullptr);
   std::unique_ptr<int, FxFreeDeleter> thing(FX_Alloc(int, 1));
@@ -46,3 +57,10 @@
   str << "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
   str << 42.0f;
 }
+
+TEST(fxcrt, FxAllocAllocatorStructException) {
+  std::vector<OnlyNumbers, FxAllocAllocator<OnlyNumbers>> vec;
+  vec.push_back({42, 73});
+  EXPECT_EQ(vec.back().x, 42);
+  EXPECT_EQ(vec.back().y, 73);
+}