[PDB] Error on too large stream directories

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
This commit is contained in:
Hans Wennborg 2023-01-27 18:33:02 +01:00
parent c6f64c5d88
commit 724b58f766
4 changed files with 45 additions and 4 deletions

View 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));
}

View 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

View 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);

View 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");
}