Convert some memset(x, 0, sz) calls to aggregate initializations.

Avoid future unsafe-buffer markings.

-- Add asserts() in cases where modification to a "distant" declaration
   of a type might subtly change the meaning.

Change-Id: I5d5c9ed80a3074e415f289ea972c393c196332a7
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/118930
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
index 4c9a016..0bef0f8 100644
--- a/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
+++ b/core/fpdfapi/parser/cpdf_security_handler_embeddertest.cpp
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <string>
+#include <type_traits>
 
 #include "build/build_config.h"
 #include "core/fpdfapi/parser/cpdf_dictionary.h"
@@ -176,8 +177,8 @@
     UnloadPage(page);
   }
   std::string new_file = GetString();
-  FPDF_FILEACCESS file_access;
-  memset(&file_access, 0, sizeof(file_access));
+  FPDF_FILEACCESS file_access = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(file_access)>);
   file_access.m_FileLen = new_file.size();
   file_access.m_GetBlock = GetBlockFromString;
   file_access.m_Param = &new_file;
diff --git a/core/fpdfdoc/cpdf_interactiveform.cpp b/core/fpdfdoc/cpdf_interactiveform.cpp
index b305fa2..fdffed2 100644
--- a/core/fpdfdoc/cpdf_interactiveform.cpp
+++ b/core/fpdfdoc/cpdf_interactiveform.cpp
@@ -7,6 +7,7 @@
 #include "core/fpdfdoc/cpdf_interactiveform.h"
 
 #include <optional>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
@@ -60,9 +61,7 @@
     return 1;
 
   PDF_FONTDATA* pData = (PDF_FONTDATA*)lParam;
-  // TODO(tsepez): investigate safety.
-  UNSAFE_BUFFERS(
-      FXSYS_memcpy(&pData->lf, &lpelfe->elfLogFont, sizeof(LOGFONTA)));
+  pData->lf = lpelfe->elfLogFont;
   pData->bFind = true;
   return 0;
 }
@@ -70,7 +69,8 @@
 bool RetrieveSpecificFont(FX_Charset charSet,
                           LPCSTR pcsFontName,
                           LOGFONTA& lf) {
-  memset(&lf, 0, sizeof(LOGFONTA));
+  lf = {};  // Aggregate initialization, not construction.
+  static_assert(std::is_aggregate_v<std::remove_reference_t<decltype(lf)>>);
   lf.lfCharSet = static_cast<int>(charSet);
   lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
   if (pcsFontName) {
@@ -79,8 +79,8 @@
     strcpy(lf.lfFaceName, pcsFontName);
   }
 
-  PDF_FONTDATA fd;
-  memset(&fd, 0, sizeof(PDF_FONTDATA));
+  PDF_FONTDATA fd = {};  // Aggregate initialization, not construction.
+  static_assert(std::is_aggregate_v<decltype(fd)>);
   HDC hDC = ::GetDC(nullptr);
   EnumFontFamiliesExA(hDC, &lf, (FONTENUMPROCA)EnumFontFamExProc, (LPARAM)&fd,
                       0);
diff --git a/core/fxcodec/gif/cfx_gifcontext_unittest.cpp b/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
index 97a9b91..b97e2de 100644
--- a/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
+++ b/core/fxcodec/gif/cfx_gifcontext_unittest.cpp
@@ -161,8 +161,7 @@
   }
   // LSD with all the values zero'd
   {
-    uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)];
-    memset(&lsd, 0, sizeof(CFX_GifLocalScreenDescriptor));
+    uint8_t lsd[sizeof(CFX_GifLocalScreenDescriptor)] = {};
     context.SetTestInputBuffer(lsd);
 
     EXPECT_EQ(GifDecoder::Status::kSuccess,
diff --git a/core/fxcodec/gif/lzw_decompressor_unittest.cpp b/core/fxcodec/gif/lzw_decompressor_unittest.cpp
index c97e92e..7d0cde9 100644
--- a/core/fxcodec/gif/lzw_decompressor_unittest.cpp
+++ b/core/fxcodec/gif/lzw_decompressor_unittest.cpp
@@ -130,8 +130,7 @@
   uint32_t image_size = std::size(image_data);
 
   uint8_t expected_data[] = {0x00};
-  uint8_t output_data[std::size(expected_data)];
-  memset(output_data, 0, sizeof(output_data));
+  uint8_t output_data[std::size(expected_data)] = {};
   uint32_t output_size = std::size(output_data);
 
   decompressor->SetSource(image_data, image_size);
@@ -162,8 +161,7 @@
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
       0x00, 0x00, 0x00, 0x00};
-  uint8_t output_data[std::size(kExpectedData)];
-  memset(output_data, 0, sizeof(output_data));
+  uint8_t output_data[std::size(kExpectedData)] = {};
   uint32_t output_size = std::size(output_data);
 
   decompressor->SetSource(kImageData, image_size);
@@ -196,8 +194,7 @@
       0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01,
       0x01, 0x01, 0x01, 0x01};
 
-  uint8_t output_data[std::size(kExpectedData)];
-  memset(output_data, 0, sizeof(output_data));
+  uint8_t output_data[std::size(kExpectedData)] = {};
   uint32_t output_size = std::size(output_data);
 
   decompressor->SetSource(kImageData, image_size);
@@ -246,8 +243,7 @@
       0xE2, 0xBE, 0xB0, 0x20, 0xCF, 0x74, 0x61, 0xDF, 0x78, 0x04};
   uint32_t image_size = std::size(kImageData);
 
-  uint8_t output_data[100];  // The uncompressed data is for a 10x10 image
-  memset(output_data, 0, sizeof(output_data));
+  uint8_t output_data[100] = {};  // The uncompressed data is for a 10x10 image
   uint32_t output_size = std::size(output_data);
 
   decompressor->SetSource(kImageData, image_size);
diff --git a/core/fxcodec/jpeg/jpegmodule.cpp b/core/fxcodec/jpeg/jpegmodule.cpp
index 59aa2b3..e86e598 100644
--- a/core/fxcodec/jpeg/jpegmodule.cpp
+++ b/core/fxcodec/jpeg/jpegmodule.cpp
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <optional>
+#include <type_traits>
 #include <utility>
 
 #include "build/build_config.h"
@@ -160,22 +161,22 @@
   static constexpr size_t kSofMarkerByteOffset = 5;
 
   jmp_buf m_JmpBuf;
-  jpeg_decompress_struct m_Cinfo;
-  jpeg_error_mgr m_Jerr;
-  jpeg_source_mgr m_Src;
+  jpeg_decompress_struct m_Cinfo = {};
+  jpeg_error_mgr m_Jerr = {};
+  jpeg_source_mgr m_Src = {};
   pdfium::raw_span<const uint8_t> m_SrcSpan;
   DataVector<uint8_t> m_ScanlineBuf;
   bool m_bInited = false;
   bool m_bStarted = false;
   bool m_bJpegTransform = false;
   uint32_t m_nDefaultScaleDenom = 1;
+
+  static_assert(std::is_aggregate_v<decltype(m_Cinfo)>);
+  static_assert(std::is_aggregate_v<decltype(m_Jerr)>);
+  static_assert(std::is_aggregate_v<decltype(m_Src)>);
 };
 
-JpegDecoder::JpegDecoder() {
-  memset(&m_Cinfo, 0, sizeof(m_Cinfo));
-  memset(&m_Jerr, 0, sizeof(m_Jerr));
-  memset(&m_Src, 0, sizeof(m_Src));
-}
+JpegDecoder::JpegDecoder() = default;
 
 JpegDecoder::~JpegDecoder() {
   if (m_bInited)
@@ -419,8 +420,8 @@
   jerr.format_message = error_do_nothing_char;
   jerr.reset_error_mgr = error_do_nothing;
 
-  jpeg_compress_struct cinfo;
-  memset(&cinfo, 0, sizeof(cinfo));
+  jpeg_compress_struct cinfo = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(cinfo)>);
   cinfo.err = &jerr;
   jpeg_create_compress(&cinfo);
   int Bpp = pSource->GetBPP() / 8;
diff --git a/core/fxcodec/jpx/jpx_unittest.cpp b/core/fxcodec/jpx/jpx_unittest.cpp
index 316d73d..c4bfc10 100644
--- a/core/fxcodec/jpx/jpx_unittest.cpp
+++ b/core/fxcodec/jpx/jpx_unittest.cpp
@@ -11,6 +11,7 @@
 #include <stdint.h>
 
 #include <limits>
+#include <type_traits>
 
 #include "core/fxcodec/jpx/cjpx_decoder.h"
 #include "core/fxcodec/jpx/jpx_decode_utils.h"
@@ -387,30 +388,30 @@
 }
 
 TEST(fxcodec, YUV420ToRGB) {
-  opj_image_comp_t u;
-  memset(&u, 0, sizeof(u));
+  opj_image_comp_t u = {};
+  static_assert(std::is_aggregate_v<decltype(u)>);
   u.dx = 1;
   u.dy = 1;
   u.w = 16;
   u.h = 16;
   u.prec = 8;
   u.bpp = 8;
-  opj_image_comp_t v;
-  memset(&v, 0, sizeof(v));
+  opj_image_comp_t v = {};
+  static_assert(std::is_aggregate_v<decltype(v)>);
   v.dx = 1;
   v.dy = 1;
   v.w = 16;
   v.h = 16;
   v.prec = 8;
   v.bpp = 8;
-  opj_image_comp_t y;
-  memset(&y, 0, sizeof(y));
+  opj_image_comp_t y = {};
+  static_assert(std::is_aggregate_v<decltype(y)>);
   y.dx = 1;
   y.dy = 1;
   y.prec = 8;
   y.bpp = 8;
-  opj_image_t img;
-  memset(&img, 0, sizeof(img));
+  opj_image_t img = {};
+  static_assert(std::is_aggregate_v<decltype(img)>);
   img.numcomps = 3;
   img.color_space = OPJ_CLRSPC_SYCC;
   img.comps = FX_Alloc(opj_image_comp_t, 3);
diff --git a/core/fxcrt/cfx_fileaccess_posix.cpp b/core/fxcrt/cfx_fileaccess_posix.cpp
index 1976a5f..c9f5ce3 100644
--- a/core/fxcrt/cfx_fileaccess_posix.cpp
+++ b/core/fxcrt/cfx_fileaccess_posix.cpp
@@ -51,15 +51,16 @@
   close(m_nFD);
   m_nFD = -1;
 }
+
 FX_FILESIZE CFX_FileAccess_Posix::GetSize() const {
   if (m_nFD < 0) {
     return 0;
   }
-  struct stat s;
-  memset(&s, 0, sizeof(s));
+  struct stat s = {};
   fstat(m_nFD, &s);
   return pdfium::checked_cast<FX_FILESIZE>(s.st_size);
 }
+
 FX_FILESIZE CFX_FileAccess_Posix::GetPosition() const {
   if (m_nFD < 0) {
     return (FX_FILESIZE)-1;
diff --git a/core/fxge/win32/cgdi_device_driver.cpp b/core/fxge/win32/cgdi_device_driver.cpp
index 721ca76..7166c5c 100644
--- a/core/fxge/win32/cgdi_device_driver.cpp
+++ b/core/fxge/win32/cgdi_device_driver.cpp
@@ -492,8 +492,7 @@
   struct {
     BITMAPINFOHEADER bmiHeader;
     uint32_t bmiColors[2];
-  } bmi;
-  memset(&bmi.bmiHeader, 0, sizeof(BITMAPINFOHEADER));
+  } bmi = {};
   bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   bmi.bmiHeader.biBitCount = 1;
   bmi.bmiHeader.biCompression = BI_RGB;
diff --git a/core/fxge/win32/cgdi_display_driver.cpp b/core/fxge/win32/cgdi_display_driver.cpp
index 23c998f..8508208 100644
--- a/core/fxge/win32/cgdi_display_driver.cpp
+++ b/core/fxge/win32/cgdi_display_driver.cpp
@@ -45,8 +45,7 @@
   HBITMAP holdbmp = (HBITMAP)SelectObject(hDCMemory, hbmp);
   BitBlt(hDCMemory, 0, 0, width, height, m_hDC, left, top, SRCCOPY);
   SelectObject(hDCMemory, holdbmp);
-  BITMAPINFO bmi;
-  memset(&bmi, 0, sizeof bmi);
+  BITMAPINFO bmi = {};
   bmi.bmiHeader.biSize = sizeof bmi.bmiHeader;
   bmi.bmiHeader.biBitCount = bitmap->GetBPP();
   bmi.bmiHeader.biHeight = -height;
diff --git a/core/fxge/win32/cwin32_platform.cpp b/core/fxge/win32/cwin32_platform.cpp
index da60945..b07c026 100644
--- a/core/fxge/win32/cwin32_platform.cpp
+++ b/core/fxge/win32/cwin32_platform.cpp
@@ -13,6 +13,7 @@
 
 #include <iterator>
 #include <memory>
+#include <type_traits>
 #include <utility>
 
 #include "core/fxcrt/byteorder.h"
@@ -200,8 +201,8 @@
 
 bool CFX_Win32FontInfo::EnumFontList(CFX_FontMapper* pMapper) {
   m_pMapper = pMapper;
-  LOGFONTA lf;
-  memset(&lf, 0, sizeof(LOGFONTA));
+  LOGFONTA lf = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(lf)>);
   lf.lfCharSet = static_cast<int>(FX_Charset::kDefault);
   lf.lfFaceName[0] = 0;
   lf.lfPitchAndFamily = 0;
diff --git a/fpdfsdk/fpdf_annot_embeddertest.cpp b/fpdfsdk/fpdf_annot_embeddertest.cpp
index 66198c6..9d1c00c 100644
--- a/fpdfsdk/fpdf_annot_embeddertest.cpp
+++ b/fpdfsdk/fpdf_annot_embeddertest.cpp
@@ -13,6 +13,7 @@
 
 #include <algorithm>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 #include "build/build_config.h"
@@ -1116,8 +1117,8 @@
   // TODO(npm): VerifySavedRendering changes annot rect dimensions by 1??
   // Open the saved document.
   std::string new_file = GetString();
-  FPDF_FILEACCESS file_access;
-  memset(&file_access, 0, sizeof(file_access));
+  FPDF_FILEACCESS file_access = {};  // Aggregate initialization
+  static_assert(std::is_aggregate_v<decltype(file_access)>);
   file_access.m_FileLen = new_file.size();
   file_access.m_GetBlock = GetBlockFromString;
   file_access.m_Param = &new_file;
diff --git a/fpdfsdk/fpdf_structtree_embeddertest.cpp b/fpdfsdk/fpdf_structtree_embeddertest.cpp
index 7d220d9..0df7829 100644
--- a/fpdfsdk/fpdf_structtree_embeddertest.cpp
+++ b/fpdfsdk/fpdf_structtree_embeddertest.cpp
@@ -58,8 +58,7 @@
     EXPECT_EQ(-1, FPDF_StructElement_GetMarkedContentID(gchild_element));
     ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, nullptr, 0));
 
-    unsigned short buffer[12];
-    memset(buffer, 0, sizeof(buffer));
+    unsigned short buffer[12] = {};
     // Deliberately pass in a small buffer size to make sure |buffer| remains
     // untouched.
     ASSERT_EQ(24U, FPDF_StructElement_GetAltText(gchild_element, buffer, 1));
@@ -456,12 +455,11 @@
     ASSERT_TRUE(element);
 
     // test nullptr inputs
-    unsigned short buffer[12];
+    unsigned short buffer[12] = {};
     ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, buffer, sizeof(buffer)));
     ASSERT_EQ(0U, FPDF_StructElement_GetType(nullptr, nullptr, 0));
     ASSERT_EQ(18U, FPDF_StructElement_GetType(element, nullptr, 0));
 
-    memset(buffer, 0, sizeof(buffer));
     // Deliberately pass in a small buffer size to make sure |buffer| remains
     // untouched.
     ASSERT_EQ(18U, FPDF_StructElement_GetType(element, buffer, 1));
@@ -574,7 +572,7 @@
     ASSERT_TRUE(element);
 
     // test nullptr inputs
-    unsigned short buffer[13];
+    unsigned short buffer[13] = {};
     ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, buffer, sizeof(buffer)));
     ASSERT_EQ(0U, FPDF_StructElement_GetTitle(nullptr, nullptr, 0));
     ASSERT_EQ(20U, FPDF_StructElement_GetTitle(element, nullptr, 0));
diff --git a/fpdfsdk/fpdf_text_embeddertest.cpp b/fpdfsdk/fpdf_text_embeddertest.cpp
index 4d55f0e..afff1ed 100644
--- a/fpdfsdk/fpdf_text_embeddertest.cpp
+++ b/fpdfsdk/fpdf_text_embeddertest.cpp
@@ -793,10 +793,9 @@
 
   EXPECT_EQ(kNumLinks, FPDFLink_CountWebLinks(pagelink));
 
-  unsigned short buffer[128];
   for (int i = 0; i < kNumLinks; i++) {
+    unsigned short buffer[128] = {};
     const size_t expected_len = strlen(kExpectedUrls[i]) + 1;
-    memset(buffer, 0, sizeof(buffer));
     EXPECT_EQ(static_cast<int>(expected_len),
               FPDFLink_GetURL(pagelink, i, nullptr, 0));
     EXPECT_EQ(static_cast<int>(expected_len),
@@ -1205,9 +1204,7 @@
       0x0073, 0x0065, 0x0072, 0x0075, 0x006D, 0x0000};
   {
     constexpr int count = std::size(soft_expected) - 1;
-    unsigned short buffer[std::size(soft_expected)];
-    memset(buffer, 0, sizeof(buffer));
-
+    unsigned short buffer[std::size(soft_expected)] = {};
     EXPECT_EQ(count + 1, FPDFText_GetText(textpage, 0, count, buffer));
     for (int i = 0; i < count; i++)
       EXPECT_EQ(soft_expected[i], buffer[i]);
diff --git a/xfa/fgas/font/cfgas_fontmgr.cpp b/xfa/fgas/font/cfgas_fontmgr.cpp
index 131fabf..c3a347e 100644
--- a/xfa/fgas/font/cfgas_fontmgr.cpp
+++ b/xfa/fgas/font/cfgas_fontmgr.cpp
@@ -16,6 +16,7 @@
 #include <algorithm>
 #include <iterator>
 #include <memory>
+#include <type_traits>
 #include <utility>
 
 #include "build/build_config.h"
@@ -188,8 +189,8 @@
   const LOGFONTW& lf = ((LPENUMLOGFONTEXW)lpelfe)->elfLogFont;
   if (lf.lfFaceName[0] == L'@')
     return 1;
-  FX_FONTDESCRIPTOR font;
-  memset(&font, 0, sizeof(FX_FONTDESCRIPTOR));
+  FX_FONTDESCRIPTOR font = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(font)>);
   font.uCharSet = FX_GetCharsetFromInt(lf.lfCharSet);
   font.dwFontStyles = GetGdiFontStyles(lf);
   FXSYS_wcsncpy(font.wsFontFace, (const wchar_t*)lf.lfFaceName, 31);
@@ -209,8 +210,8 @@
     return fonts;
   }
 
-  LOGFONTW lfFind;
-  memset(&lfFind, 0, sizeof(lfFind));
+  LOGFONTW lfFind = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(lfFind)>);
   lfFind.lfCharSet = DEFAULT_CHARSET;
   if (pwsFaceName) {
     FXSYS_wcsncpy(lfFind.lfFaceName, pwsFaceName, 31);
@@ -271,8 +272,8 @@
                                                  FX_CodePage wCodePage,
                                                  uint32_t dwUSB,
                                                  wchar_t wUnicode) {
-  FX_FONTMATCHPARAMS params;
-  memset(&params, 0, sizeof(params));
+  FX_FONTMATCHPARAMS params = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(params)>);
   params.dwUSB = dwUSB;
   params.wUnicode = wUnicode;
   params.wCodePage = wCodePage;
@@ -528,8 +529,8 @@
   ftStream->read = ftStreamRead;
   ftStream->close = ftStreamClose;
 
-  FT_Open_Args ftArgs;
-  memset(&ftArgs, 0, sizeof(FT_Open_Args));
+  FT_Open_Args ftArgs = {};  // Aggregate initialization.
+  static_assert(std::is_aggregate_v<decltype(ftArgs)>);
   ftArgs.flags |= FT_OPEN_STREAM;
   ftArgs.stream = ftStream;