[PDB] Error on too large stream directories
authorHans Wennborg <hans@chromium.org>
Fri, 27 Jan 2023 17:33:02 +0000 (18:33 +0100)
committerHans Wennborg <hans@chromium.org>
Fri, 24 Feb 2023 14:07:11 +0000 (15:07 +0100)
We hit this in Chromium builds where the PDB file was just under 4GB,
but the stream directory was actually too large to be correctly
represented.

llvm-pdbutil would error about this in llvm::msf::validateSuperBlock,
but lld should not write such PDB files in the first place.

Differential revision: https://reviews.llvm.org/D144385

lld/COFF/PDB.cpp
llvm/include/llvm/DebugInfo/MSF/MSFError.h
llvm/lib/DebugInfo/MSF/MSFBuilder.cpp
llvm/lib/DebugInfo/MSF/MSFError.cpp

index 745afab..94af920 100644 (file)
@@ -31,6 +31,7 @@
 #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
 #include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFError.h"
 #include "llvm/DebugInfo/PDB/GenericError.h"
 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
@@ -1687,6 +1688,12 @@ void PDBLinker::commit(codeview::GUID *guid) {
   // the user can see the output of /time and /summary, which is very helpful
   // when trying to figure out why a PDB file is too large.
   if (Error e = builder.commit(ctx.config.pdbPath, guid)) {
+    e = handleErrors(std::move(e),
+        [](const llvm::msf::MSFError &me) {
+          error(me.message());
+          if (me.isPageOverflow())
+            error("try setting a larger /pdbpagesize");
+        });
     checkError(std::move(e));
     error("failed to write PDB file " + Twine(ctx.config.pdbPath));
   }
index b84f9d7..88c823f 100644 (file)
@@ -16,14 +16,15 @@ namespace msf {
 enum class msf_error_code {
   unspecified = 1,
   insufficient_buffer,
+  not_writable,
+  no_stream,
+  invalid_format,
+  block_in_use,
   size_overflow_4096,
   size_overflow_8192,
   size_overflow_16384,
   size_overflow_32768,
-  not_writable,
-  no_stream,
-  invalid_format,
-  block_in_use
+  stream_directory_overflow,
 };
 } // namespace msf
 } // namespace llvm
@@ -46,6 +47,25 @@ class MSFError : public ErrorInfo<MSFError, StringError> {
 public:
   using ErrorInfo<MSFError, StringError>::ErrorInfo; // inherit constructors
   MSFError(const Twine &S) : ErrorInfo(S, msf_error_code::unspecified) {}
+
+  bool isPageOverflow() const {
+    switch (static_cast<msf_error_code>(convertToErrorCode().value())) {
+    case msf_error_code::unspecified:
+    case msf_error_code::insufficient_buffer:
+    case msf_error_code::not_writable:
+    case msf_error_code::no_stream:
+    case msf_error_code::invalid_format:
+    case msf_error_code::block_in_use:
+      return false;
+    case msf_error_code::size_overflow_4096:
+    case msf_error_code::size_overflow_8192:
+    case msf_error_code::size_overflow_16384:
+    case msf_error_code::size_overflow_32768:
+    case msf_error_code::stream_directory_overflow:
+      return true;
+    }
+  }
+
   static char ID;
 };
 } // namespace msf
index f9a763d..c26caa6 100644 (file)
@@ -364,6 +364,18 @@ Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path,
                 FileSize, Layout.SB->BlockSize));
   }
 
+  uint64_t NumDirectoryBlocks =
+      bytesToBlocks(Layout.SB->NumDirectoryBytes, Layout.SB->BlockSize);
+  uint64_t DirectoryBlockMapSize =
+      NumDirectoryBlocks * sizeof(support::ulittle32_t);
+  if (DirectoryBlockMapSize > Layout.SB->BlockSize) {
+    return make_error<MSFError>(msf_error_code::stream_directory_overflow,
+                                formatv("The directory block map ({0} bytes) "
+                                        "doesn't fit in a block ({1} bytes)",
+                                        DirectoryBlockMapSize,
+                                        Layout.SB->BlockSize));
+  }
+
   auto OutFileOrError = FileOutputBuffer::create(Path, FileSize);
   if (auto EC = OutFileOrError.takeError())
     return std::move(EC);
index fd93c3e..dbd8648 100644 (file)
@@ -43,6 +43,8 @@ public:
       return "The data is in an unexpected format.";
     case msf_error_code::block_in_use:
       return "The block is already in use.";
+    case msf_error_code::stream_directory_overflow:
+      return "PDB stream directory too large.";
     }
     llvm_unreachable("Unrecognized msf_error_code");
   }