[memprof] Align each rawprofile section to 8b.

The first 8b of each raw profile section need to be aligned to 8b since
the first item in each section is a u64 count of the number of items in
the section.
Summary of changes:
* Assert alignment when reading counts.
* Update test to check alignment, relax some size checks to allow padding.
* Update raw binary inputs for llvm-profdata tests.

Differential Revision: https://reviews.llvm.org/D114826

GitOrigin-RevId: 3a4d373ec2ba676dc91fba06631a776785f8a6eb
diff --git a/lib/memprof/memprof_rawprofile.cpp b/lib/memprof/memprof_rawprofile.cpp
index 48e579c..c4800a6 100644
--- a/lib/memprof/memprof_rawprofile.cpp
+++ b/lib/memprof/memprof_rawprofile.cpp
@@ -6,6 +6,7 @@
 #include "memprof_rawprofile.h"
 #include "profile/MemProfData.inc"
 #include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
@@ -77,7 +78,7 @@
 
   // Store the number of segments we recorded in the space we reserved.
   *((u64 *)Buffer) = NumSegmentsRecorded;
-  CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+  CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
         "Expected num bytes != actual bytes written");
 }
 
@@ -132,7 +133,7 @@
     *(u64 *)(Ptr - (Count + 1) * sizeof(u64)) = Count;
   }
 
-  CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+  CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
         "Expected num bytes != actual bytes written");
 }
 
@@ -160,7 +161,7 @@
     Ptr = WriteBytes((*h)->mib, Ptr);
   }
 
-  CHECK(ExpectedNumBytes == static_cast<u64>(Ptr - Buffer) &&
+  CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
         "Expected num bytes != actual bytes written");
 }
 
@@ -181,11 +182,15 @@
 // BuildID 32B
 // ----------
 // ...
+// ----------
+// Optional Padding Bytes
 // ---------- MIB Info
 // Num Entries
 // ---------- MIB Entry
 // Alloc Count
 // ...
+// ----------
+// Optional Padding Bytes
 // ---------- Stack Info
 // Num Entries
 // ---------- Stack Entry
@@ -194,23 +199,29 @@
 // PC2
 // ...
 // ----------
+// Optional Padding Bytes
 // ...
 u64 SerializeToRawProfile(MIBMapTy &MIBMap, MemoryMappingLayoutBase &Layout,
                           char *&Buffer) {
-  const u64 NumSegmentBytes = SegmentSizeBytes(Layout);
+  // Each section size is rounded up to 8b since the first entry in each section
+  // is a u64 which holds the number of entries in the section by convention.
+  const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Layout), 8);
 
   Vector<u64> StackIds;
   MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
   // The first 8b are for the total number of MIB records. Each MIB record is
   // preceded by a 8b stack id which is associated with stack frames in the next
   // section.
-  const u64 NumMIBInfoBytes =
-      sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock));
+  const u64 NumMIBInfoBytes = RoundUpTo(
+      sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8);
 
-  const u64 NumStackBytes = StackSizeBytes(StackIds);
+  const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
 
-  const u64 TotalSizeBytes =
-      sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes;
+  // Ensure that the profile is 8b aligned. We allow for some optional padding
+  // at the end so that any subsequent profile serialized to the same file does
+  // not incur unaligned accesses.
+  const u64 TotalSizeBytes = RoundUpTo(
+      sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8);
 
   // Allocate the memory for the entire buffer incl. info blocks.
   Buffer = (char *)InternalAlloc(TotalSizeBytes);
diff --git a/lib/memprof/tests/rawprofile.cpp b/lib/memprof/tests/rawprofile.cpp
index 29bc3b5..829e183 100644
--- a/lib/memprof/tests/rawprofile.cpp
+++ b/lib/memprof/tests/rawprofile.cpp
@@ -49,6 +49,8 @@
 
 template <class T = u64> T Read(char *&Buffer) {
   static_assert(std::is_pod<T>::value, "Must be a POD type.");
+  assert(reinterpret_cast<size_t>(Buffer) % sizeof(T) == 0 &&
+         "Unaligned read!");
   T t = *reinterpret_cast<T *>(Buffer);
   Buffer += sizeof(T);
   return t;
@@ -103,8 +105,9 @@
   const u64 MIBOffset = Read(Ptr);
   const u64 StackOffset = Read(Ptr);
 
-  // ============= Check sizes.
+  // ============= Check sizes and padding.
   EXPECT_EQ(TotalSize, NumBytes);
+  EXPECT_EQ(TotalSize % 8, 0ULL);
 
   // Should be equal to the size of the raw profile header.
   EXPECT_EQ(SegmentOffset, 48ULL);
@@ -120,8 +123,10 @@
 
   EXPECT_EQ(StackOffset, 336ULL);
   // We expect 2 stack entries, with 5 frames - 8b for total count,
-  // 2 * (8b for id, 8b for frame count and 5*8b for fake frames)
-  EXPECT_EQ(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));
+  // 2 * (8b for id, 8b for frame count and 5*8b for fake frames).
+  // Since this is the last section, there may be additional padding at the end
+  // to make the total profile size 8b aligned.
+  EXPECT_GE(TotalSize - StackOffset, 8ULL + 2 * (8 + 8 + 5 * 8));
 
   // ============= Check contents.
   unsigned char ExpectedSegmentBytes[64] = {