Add FX_AllocUninit() and FX_AllocUninit2D().

Add functions that are similar to FX_Alloc() and FX_Alloc2D(), but do
not initialize the allocated memory. Use them in some places that
immediately writes into the allocated memory.

Bug: pdfium:1171
Change-Id: If5aac228d3f237aff3bc5cf96bb1af9d5443d5fe
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/68170
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index 62c3df5..faa62a2 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -405,7 +405,7 @@
       "q 1 0 0 1 0 0 cm 3.102 4.6700001 m 5.4500012 .28999999 "
       "l 4.2399998 3.1499999 4.65 2.98 3.456 0.24 c 3.102 4.6700001 l h f Q\n";
   size_t buf_len = FX_ArraySize(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len));
+  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, buf_len));
   memcpy(buf.get(), content, buf_len);
   auto pStream = pdfium::MakeRetain<CPDF_Stream>(std::move(buf), buf_len,
                                                  std::move(pDict));
diff --git a/core/fpdfapi/page/cpdf_image.cpp b/core/fpdfapi/page/cpdf_image.cpp
index 68703c4..3861e45 100644
--- a/core/fpdfapi/page/cpdf_image.cpp
+++ b/core/fpdfapi/page/cpdf_image.cpp
@@ -268,7 +268,7 @@
     pMaskDict->SetNewFor<CPDF_Name>("ColorSpace", "DeviceGray");
     pMaskDict->SetNewFor<CPDF_Number>("BitsPerComponent", 8);
     if (pMaskBitmap->GetFormat() != FXDIB_1bppMask) {
-      mask_buf.reset(FX_Alloc2D(uint8_t, maskHeight, maskWidth));
+      mask_buf.reset(FX_AllocUninit2D(uint8_t, maskHeight, maskWidth));
       mask_size = maskHeight * maskWidth;  // Safe since checked alloc returned.
       for (int32_t a = 0; a < maskHeight; a++) {
         memcpy(mask_buf.get() + a * maskWidth, pMaskBitmap->GetScanline(a),
diff --git a/core/fpdfapi/page/cpdf_streamparser.cpp b/core/fpdfapi/page/cpdf_streamparser.cpp
index aa8a27b..26857f4 100644
--- a/core/fpdfapi/page/cpdf_streamparser.cpp
+++ b/core/fpdfapi/page/cpdf_streamparser.cpp
@@ -170,7 +170,7 @@
   uint32_t dwStreamSize;
   if (decoder.IsEmpty()) {
     dwOrigSize = std::min<uint32_t>(dwOrigSize, m_pBuf.size() - m_Pos);
-    pData.reset(FX_Alloc(uint8_t, dwOrigSize));
+    pData.reset(FX_AllocUninit(uint8_t, dwOrigSize));
     auto copy_span = m_pBuf.subspan(m_Pos, dwOrigSize);
     memcpy(pData.get(), copy_span.data(), copy_span.size());
     dwStreamSize = dwOrigSize;
@@ -200,7 +200,7 @@
       dwStreamSize += m_Pos - dwPrevPos;
     }
     m_Pos = dwSavePos;
-    pData.reset(FX_Alloc(uint8_t, dwStreamSize));
+    pData.reset(FX_AllocUninit(uint8_t, dwStreamSize));
     auto copy_span = m_pBuf.subspan(m_Pos, dwStreamSize);
     memcpy(pData.get(), copy_span.data(), copy_span.size());
     m_Pos += dwStreamSize;
diff --git a/core/fpdfapi/parser/cpdf_object_unittest.cpp b/core/fpdfapi/parser/cpdf_object_unittest.cpp
index 8ad3104..08fdfeb 100644
--- a/core/fpdfapi/parser/cpdf_object_unittest.cpp
+++ b/core/fpdfapi/parser/cpdf_object_unittest.cpp
@@ -71,7 +71,8 @@
     // Stream object.
     const char content[] = "abcdefghijklmnopqrstuvwxyz";
     size_t buf_len = FX_ArraySize(content);
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len));
+    std::unique_ptr<uint8_t, FxFreeDeleter> buf(
+        FX_AllocUninit(uint8_t, buf_len));
     memcpy(buf.get(), content, buf_len);
     auto pNewDict = pdfium::MakeRetain<CPDF_Dictionary>();
     m_StreamDictObj = pNewDict;
@@ -612,7 +613,7 @@
       uint8_t content[] = "content: this is a stream";
       size_t data_size = FX_ArraySize(content);
       std::unique_ptr<uint8_t, FxFreeDeleter> data(
-          FX_Alloc(uint8_t, data_size));
+          FX_AllocUninit(uint8_t, data_size));
       memcpy(data.get(), content, data_size);
       stream_vals[i] =
           arr->AppendNew<CPDF_Stream>(std::move(data), data_size, vals[i]);
@@ -658,7 +659,8 @@
     // The data buffer will be owned by stream object, so it needs to be
     // dynamically allocated.
     size_t buf_size = sizeof(data);
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_size));
+    std::unique_ptr<uint8_t, FxFreeDeleter> buf(
+        FX_AllocUninit(uint8_t, buf_size));
     memcpy(buf.get(), data, buf_size);
     CPDF_Stream* stream_val = arr->InsertNewAt<CPDF_Stream>(
         13, std::move(buf), buf_size, stream_dict);
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index 4b5ef5c..8237338 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -130,7 +130,7 @@
 void CPDF_Stream::SetData(pdfium::span<const uint8_t> pData) {
   std::unique_ptr<uint8_t, FxFreeDeleter> data_copy;
   if (!pData.empty()) {
-    data_copy.reset(FX_Alloc(uint8_t, pData.size()));
+    data_copy.reset(FX_AllocUninit(uint8_t, pData.size()));
     memcpy(data_copy.get(), pData.data(), pData.size());
   }
   TakeData(std::move(data_copy), pData.size());
diff --git a/core/fpdfapi/parser/cpdf_stream_acc.cpp b/core/fpdfapi/parser/cpdf_stream_acc.cpp
index 23c314f..ef16ffe 100644
--- a/core/fpdfapi/parser/cpdf_stream_acc.cpp
+++ b/core/fpdfapi/parser/cpdf_stream_acc.cpp
@@ -91,7 +91,7 @@
     m_dwSize = 0;
     return p;
   }
-  std::unique_ptr<uint8_t, FxFreeDeleter> p(FX_Alloc(uint8_t, m_dwSize));
+  std::unique_ptr<uint8_t, FxFreeDeleter> p(FX_AllocUninit(uint8_t, m_dwSize));
   memcpy(p.get(), m_pData.Get(), m_dwSize);
   return p;
 }
diff --git a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
index bad221e..cd38bcc 100644
--- a/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
+++ b/core/fpdfapi/render/cpdf_docrenderdata_unittest.cpp
@@ -89,7 +89,7 @@
 
   static const char content[] = "1234";
   size_t len = FX_ArraySize(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
+  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
   memcpy(buf.get(), content, len);
   return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
                                          std::move(func_dict));
@@ -131,7 +131,7 @@
 
   static const char content[] = "{ 360 mul sin 2 div }";
   size_t len = FX_ArraySize(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
+  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
   memcpy(buf.get(), content, len);
   return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
                                          std::move(func_dict));
@@ -151,7 +151,7 @@
 
   static const char content[] = "garbage";
   size_t len = FX_ArraySize(content);
-  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
+  std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, len));
   memcpy(buf.get(), content, len);
   return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
                                          std::move(func_dict));
diff --git a/core/fpdfdoc/cpdf_filespec_unittest.cpp b/core/fpdfdoc/cpdf_filespec_unittest.cpp
index a075c5e..daeee4e 100644
--- a/core/fpdfdoc/cpdf_filespec_unittest.cpp
+++ b/core/fpdfdoc/cpdf_filespec_unittest.cpp
@@ -210,7 +210,8 @@
       // Set the file stream.
       auto pDict = pdfium::MakeRetain<CPDF_Dictionary>();
       size_t buf_len = strlen(streams[i]) + 1;
-      std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, buf_len));
+      std::unique_ptr<uint8_t, FxFreeDeleter> buf(
+          FX_AllocUninit(uint8_t, buf_len));
       memcpy(buf.get(), streams[i], buf_len);
       file_dict->SetNewFor<CPDF_Stream>(keys[i], std::move(buf), buf_len,
                                         std::move(pDict));
@@ -247,7 +248,7 @@
     CPDF_Dictionary* file_dict =
         file_spec.GetObj()->AsDictionary()->GetDictFor("EF");
     auto pDict = pdfium::MakeRetain<CPDF_Dictionary>();
-    std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, 6));
+    std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_AllocUninit(uint8_t, 6));
     memcpy(buf.get(), "hello", 6);
     file_dict->SetNewFor<CPDF_Stream>("UF", std::move(buf), 6,
                                       std::move(pDict));
diff --git a/core/fxcodec/progressivedecoder.cpp b/core/fxcodec/progressivedecoder.cpp
index e948b39..73fdf2a 100644
--- a/core/fxcodec/progressivedecoder.cpp
+++ b/core/fxcodec/progressivedecoder.cpp
@@ -760,7 +760,7 @@
   m_clipBox = FX_RECT(0, 0, m_SrcWidth, m_SrcHeight);
   m_pBmpContext = std::move(pBmpContext);
   if (m_SrcPaletteNumber) {
-    m_pSrcPalette.reset(FX_Alloc(FX_ARGB, m_SrcPaletteNumber));
+    m_pSrcPalette.reset(FX_AllocUninit(FX_ARGB, m_SrcPaletteNumber));
     memcpy(m_pSrcPalette.get(), palette->data(),
            m_SrcPaletteNumber * sizeof(FX_ARGB));
   } else {
diff --git a/core/fxcodec/tiff/tiffmodule.cpp b/core/fxcodec/tiff/tiffmodule.cpp
index 179fca6..c1f4c7b 100644
--- a/core/fxcodec/tiff/tiffmodule.cpp
+++ b/core/fxcodec/tiff/tiffmodule.cpp
@@ -209,7 +209,7 @@
   if (!buf)
     return;
   size_t size = strlen(buf);
-  uint8_t* ptr = FX_Alloc(uint8_t, size + 1);
+  uint8_t* ptr = FX_AllocUninit(uint8_t, size + 1);
   memcpy(ptr, buf, size);
   ptr[size] = 0;
   pAttr->m_Exif[tag] = ptr;
diff --git a/core/fxcrt/fx_memory.cpp b/core/fxcrt/fx_memory.cpp
index 9a9dd95..f2b47f0 100644
--- a/core/fxcrt/fx_memory.cpp
+++ b/core/fxcrt/fx_memory.cpp
@@ -73,6 +73,33 @@
 
 namespace internal {
 
+void* Alloc(size_t num_members, size_t member_size) {
+  FX_SAFE_SIZE_T total = member_size;
+  total *= num_members;
+  if (!total.IsValid())
+    return nullptr;
+
+  constexpr int kFlags = pdfium::base::PartitionAllocReturnNull;
+  return pdfium::base::PartitionAllocGenericFlags(
+      GetGeneralPartitionAllocator().root(), kFlags, total.ValueOrDie(),
+      "GeneralPartition");
+}
+
+void* AllocOrDie(size_t num_members, size_t member_size) {
+  void* result = Alloc(num_members, member_size);
+  if (!result)
+    FX_OutOfMemoryTerminate();  // Never returns.
+
+  return result;
+}
+
+void* AllocOrDie2D(size_t w, size_t h, size_t member_size) {
+  if (w >= std::numeric_limits<size_t>::max() / h)
+    FX_OutOfMemoryTerminate();  // Never returns.
+
+  return AllocOrDie(w * h, member_size);
+}
+
 void* Calloc(size_t num_members, size_t member_size) {
   FX_SAFE_SIZE_T total = member_size;
   total *= num_members;
@@ -99,7 +126,6 @@
 }
 
 void* CallocOrDie(size_t num_members, size_t member_size) {
-  // TODO(tsepez): See if we can avoid the implicit memset(0).
   void* result = Calloc(num_members, member_size);
   if (!result)
     FX_OutOfMemoryTerminate();  // Never returns.
diff --git a/core/fxcrt/fx_memory.h b/core/fxcrt/fx_memory.h
index d8f6661..63efd08 100644
--- a/core/fxcrt/fx_memory.h
+++ b/core/fxcrt/fx_memory.h
@@ -45,8 +45,19 @@
 #define FX_TryRealloc(type, ptr, size) \
   static_cast<type*>(internal::Realloc(ptr, size, sizeof(type)))
 
+// These never return nullptr, but return uninitialized memory.
+// TOOD(thestig): Add FX_TryAllocUninit() if there is a use case.
+#define FX_AllocUninit(type, size) \
+  static_cast<type*>(internal::AllocOrDie(size, sizeof(type)))
+#define FX_AllocUninit2D(type, w, h) \
+  static_cast<type*>(internal::AllocOrDie2D(w, h, sizeof(type)))
+
 namespace internal {
 
+void* Alloc(size_t num_members, size_t member_size);
+void* AllocOrDie(size_t num_members, size_t member_size);
+void* AllocOrDie2D(size_t w, size_t h, size_t member_size);
+
 void* Calloc(size_t num_members, size_t member_size);
 void* Realloc(void* ptr, size_t num_members, size_t member_size);
 void* CallocOrDie(size_t num_members, size_t member_size);
diff --git a/fpdfsdk/fpdf_attachment.cpp b/fpdfsdk/fpdf_attachment.cpp
index 7f55691..fcad33f 100644
--- a/fpdfsdk/fpdf_attachment.cpp
+++ b/fpdfsdk/fpdf_attachment.cpp
@@ -251,7 +251,7 @@
       true);
 
   // Create the file stream and have the filespec dictionary link to it.
-  std::unique_ptr<uint8_t, FxFreeDeleter> stream(FX_Alloc(uint8_t, len));
+  std::unique_ptr<uint8_t, FxFreeDeleter> stream(FX_AllocUninit(uint8_t, len));
   memcpy(stream.get(), contents, len);
   CPDF_Stream* pFileStream = pDoc->NewIndirect<CPDF_Stream>(
       std::move(stream), len, std::move(pFileStreamDict));
diff --git a/third_party/agg23/agg_array.h b/third_party/agg23/agg_array.h
index 8dcb0af..fba41a7 100644
--- a/third_party/agg23/agg_array.h
+++ b/third_party/agg23/agg_array.h
@@ -126,7 +126,7 @@
 {
     if(new_size > m_size) {
         if(new_size > m_capacity) {
-            T* data = FX_Alloc(T, new_size);
+            T* data = FX_AllocUninit(T, new_size);
             memcpy(data, m_array, m_size * sizeof(T));
             FX_Free(m_array);
             m_array = data;
@@ -318,7 +318,7 @@
 {
     unsigned i;
     for(i = 0; i < v.m_num_blocks; ++i) {
-        m_blocks[i] = FX_Alloc(T, block_size);
+        m_blocks[i] = FX_AllocUninit(T, block_size);
         memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
     }
 }