[llvm] effc333 - [llvm-cov] Enforce alignment of function records

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 25 01:56:14 PDT 2021


Author: serge-sans-paille
Date: 2021-06-25T10:56:06+02:00
New Revision: effc3339f6c7702357471efc849c4fc31b4b1aad

URL: https://github.com/llvm/llvm-project/commit/effc3339f6c7702357471efc849c4fc31b4b1aad
DIFF: https://github.com/llvm/llvm-project/commit/effc3339f6c7702357471efc849c4fc31b4b1aad.diff

LOG: [llvm-cov] Enforce alignment of function records

Function Records are required to be aligned on 8 bytes. This is enforced for each
records except the first, when one relies on the default alignment within an
std::string. There's no such guarantee, and indeed on 32 bits for some
implementation of std::string this is not enforced.

Provide a portable implementation based on llvm's MemoryBuffer.

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

Added: 
    

Modified: 
    llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
    llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
index eb71bf6c8975c..242ffdd16e3f2 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h
@@ -179,6 +179,8 @@ class BinaryCoverageReader : public CoverageMappingReader {
           FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
   };
 
+  using FuncRecordsStorage = std::unique_ptr<MemoryBuffer>;
+
 private:
   std::vector<std::string> Filenames;
   std::vector<ProfileMappingRecord> MappingRecords;
@@ -191,9 +193,9 @@ class BinaryCoverageReader : public CoverageMappingReader {
   // Used to tie the lifetimes of coverage function records to the lifetime of
   // this BinaryCoverageReader instance. Needed to support the format change in
   // D69471, which can split up function records into multiple sections on ELF.
-  std::string FuncRecords;
+  FuncRecordsStorage FuncRecords;
 
-  BinaryCoverageReader(std::string &&FuncRecords)
+  BinaryCoverageReader(FuncRecordsStorage &&FuncRecords)
       : FuncRecords(std::move(FuncRecords)) {}
 
 public:
@@ -206,7 +208,8 @@ class BinaryCoverageReader : public CoverageMappingReader {
          StringRef CompilationDir = "");
 
   static Expected<std::unique_ptr<BinaryCoverageReader>>
-  createCoverageReaderFromBuffer(StringRef Coverage, std::string &&FuncRecords,
+  createCoverageReaderFromBuffer(StringRef Coverage,
+                                 FuncRecordsStorage &&FuncRecords,
                                  InstrProfSymtab &&ProfileNames,
                                  uint8_t BytesInAddress,
                                  support::endianness Endian,

diff  --git a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
index 4fbcefd236cbe..9fffb249e72db 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp
@@ -824,13 +824,13 @@ static const char *TestingFormatMagic = "llvmcovmtestdata";
 
 Expected<std::unique_ptr<BinaryCoverageReader>>
 BinaryCoverageReader::createCoverageReaderFromBuffer(
-    StringRef Coverage, std::string &&FuncRecords,
+    StringRef Coverage, FuncRecordsStorage &&FuncRecords,
     InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress,
     support::endianness Endian, StringRef CompilationDir) {
   std::unique_ptr<BinaryCoverageReader> Reader(
       new BinaryCoverageReader(std::move(FuncRecords)));
   Reader->ProfileNames = std::move(ProfileNames);
-  StringRef FuncRecordsRef = Reader->FuncRecords;
+  StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer();
   if (BytesInAddress == 4 && Endian == support::endianness::little) {
     if (Error E =
             readCoverageMappingData<uint32_t, support::endianness::little>(
@@ -895,11 +895,13 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
       Data.substr(0, sizeof(CovMapHeader)).data());
   CovMapVersion Version =
       (CovMapVersion)CovHeader->getVersion<support::endianness::little>();
-  StringRef CoverageMapping, CoverageRecords;
+  StringRef CoverageMapping;
+  BinaryCoverageReader::FuncRecordsStorage CoverageRecords;
   if (Version < CovMapVersion::Version4) {
     CoverageMapping = Data;
     if (CoverageMapping.empty())
       return make_error<CoverageMapError>(coveragemap_error::truncated);
+    CoverageRecords = MemoryBuffer::getMemBuffer("");
   } else {
     uint32_t FilenamesSize =
         CovHeader->getFilenamesSize<support::endianness::little>();
@@ -913,12 +915,12 @@ loadTestingFormat(StringRef Data, StringRef CompilationDir) {
     Pad = offsetToAlignedAddr(Data.data(), Align(8));
     if (Data.size() < Pad)
       return make_error<CoverageMapError>(coveragemap_error::malformed);
-    CoverageRecords = Data.substr(Pad);
-    if (CoverageRecords.empty())
+    CoverageRecords = MemoryBuffer::getMemBuffer(Data.substr(Pad));
+    if (CoverageRecords->getBufferSize() == 0)
       return make_error<CoverageMapError>(coveragemap_error::truncated);
   }
   return BinaryCoverageReader::createCoverageReaderFromBuffer(
-      CoverageMapping, CoverageRecords.str(), std::move(ProfileNames),
+      CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames),
       BytesInAddress, Endian, CompilationDir);
 }
 
@@ -1003,21 +1005,49 @@ loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
     return std::move(E);
 
   // Look for the coverage records section (Version4 only).
-  std::string FuncRecords;
   auto CoverageRecordsSections =
       lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
                                                   /*AddSegmentInfo=*/false));
-  if (auto E = CoverageRecordsSections.takeError())
+
+  BinaryCoverageReader::FuncRecordsStorage FuncRecords;
+  if (auto E = CoverageRecordsSections.takeError()) {
     consumeError(std::move(E));
-  else {
+    FuncRecords = MemoryBuffer::getMemBuffer("");
+  } else {
+    // Compute the FuncRecordsBuffer of the buffer, taking into account the
+    // padding between each record, and making sure the first block is aligned
+    // in memory to maintain consistency between buffer address and size
+    // alignment.
+    const Align RecordAlignment(8);
+    uint64_t FuncRecordsSize = 0;
+    for (SectionRef Section : *CoverageRecordsSections) {
+      auto CoverageRecordsOrErr = Section.getContents();
+      if (!CoverageRecordsOrErr)
+        return CoverageRecordsOrErr.takeError();
+      FuncRecordsSize += alignTo(CoverageRecordsOrErr->size(), RecordAlignment);
+    }
+    auto WritableBuffer =
+        WritableMemoryBuffer::getNewUninitMemBuffer(FuncRecordsSize);
+    char *FuncRecordsBuffer = WritableBuffer->getBufferStart();
+    assert(isAddrAligned(RecordAlignment, FuncRecordsBuffer) &&
+           "Allocated memory is correctly aligned");
+
     for (SectionRef Section : *CoverageRecordsSections) {
       auto CoverageRecordsOrErr = Section.getContents();
       if (!CoverageRecordsOrErr)
         return CoverageRecordsOrErr.takeError();
-      FuncRecords += CoverageRecordsOrErr.get();
-      while (FuncRecords.size() % 8 != 0)
-        FuncRecords += '\0';
+      const auto &CoverageRecords = CoverageRecordsOrErr.get();
+      FuncRecordsBuffer = std::copy(CoverageRecords.begin(),
+                                    CoverageRecords.end(), FuncRecordsBuffer);
+      FuncRecordsBuffer =
+          std::fill_n(FuncRecordsBuffer,
+                      alignAddr(FuncRecordsBuffer, RecordAlignment) -
+                          (uintptr_t)FuncRecordsBuffer,
+                      '\0');
     }
+    assert(FuncRecordsBuffer == WritableBuffer->getBufferEnd() &&
+           "consistent init");
+    FuncRecords = std::move(WritableBuffer);
   }
 
   return BinaryCoverageReader::createCoverageReaderFromBuffer(


        


More information about the llvm-commits mailing list