diff options
author | Justin Bogner <mail@justinbogner.com> | 2014-10-14 00:57:34 +0000 |
---|---|---|
committer | Justin Bogner <mail@justinbogner.com> | 2014-10-14 00:57:34 +0000 |
commit | bd272ece3ffe5fbe65596643aa2d7d6adf6f98d5 (patch) | |
tree | ac363f23e07024fc3844a6dd473e6fa5f81a9675 /tools/libclang/CXLoadedDiagnostic.cpp | |
parent | 54898363ff76ff1bd5dd2ee569b909625002be7f (diff) |
Revert "Frontend: Extract SerializedDiagnosticReader out of CXLoadedDiagnostic (NFC)"
The bots can't seem to find an include file. Reverting for now and
I'll look into it in a bit.
This reverts commits r219647 and r219648.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219649 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/libclang/CXLoadedDiagnostic.cpp')
-rw-r--r-- | tools/libclang/CXLoadedDiagnostic.cpp | 591 |
1 files changed, 429 insertions, 162 deletions
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp index c923b26be9..0e0075fc38 100644 --- a/tools/libclang/CXLoadedDiagnostic.cpp +++ b/tools/libclang/CXLoadedDiagnostic.cpp @@ -16,8 +16,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" -#include "clang/Frontend/SerializedDiagnostics.h" -#include "clang/Frontend/SerializedDiagnosticReader.h" +#include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -184,207 +183,475 @@ void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location, // Deserialize diagnostics. //===----------------------------------------------------------------------===// +enum { MaxSupportedVersion = 2 }; +typedef SmallVector<uint64_t, 64> RecordData; +enum LoadResult { Failure = 1, Success = 0 }; +enum StreamResult { Read_EndOfStream, + Read_BlockBegin, + Read_Failure, + Read_Record, + Read_BlockEnd }; + namespace { -class DiagLoader : serialized_diags::SerializedDiagnosticReader { +class DiagLoader { enum CXLoadDiag_Error *error; CXString *errorString; - std::unique_ptr<CXLoadedDiagnosticSetImpl> TopDiags; - SmallVector<std::unique_ptr<CXLoadedDiagnostic>, 8> CurrentDiags; - - std::error_code reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) { + + void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) { if (error) *error = code; if (errorString) *errorString = cxstring::createDup(err); - return serialized_diags::SDError::HandlerFailed; } - std::error_code reportInvalidFile(llvm::StringRef err) { + void reportInvalidFile(llvm::StringRef err) { return reportBad(CXLoadDiag_InvalidFile, err); } - std::error_code readRange(const serialized_diags::Location &SDStart, - const serialized_diags::Location &SDEnd, - CXSourceRange &SR); - - std::error_code readLocation(const serialized_diags::Location &SDLoc, - CXLoadedDiagnostic::Location &LoadedLoc); - -protected: - std::error_code visitStartOfDiagnostic() override; - std::error_code visitEndOfDiagnostic() override; - - std::error_code visitCategoryRecord(unsigned ID, StringRef Name) override; - - std::error_code visitDiagFlagRecord(unsigned ID, StringRef Name) override; - - std::error_code visitDiagnosticRecord( - unsigned Severity, const serialized_diags::Location &Location, - unsigned Category, unsigned Flag, StringRef Message) override; - - std::error_code visitFilenameRecord(unsigned ID, unsigned Size, - unsigned Timestamp, - StringRef Name) override; - - std::error_code visitFixitRecord(const serialized_diags::Location &Start, - const serialized_diags::Location &End, - StringRef CodeToInsert) override; - - std::error_code - visitSourceRangeRecord(const serialized_diags::Location &Start, - const serialized_diags::Location &End) override; - + LoadResult readMetaBlock(llvm::BitstreamCursor &Stream); + + LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream, + CXDiagnosticSetImpl &Diags, + CXLoadedDiagnosticSetImpl &TopDiags); + + StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream, + llvm::StringRef errorContext, + unsigned &BlockOrRecordID, + bool atTopLevel = false); + + + LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags, + Strings &strings, llvm::StringRef errorContext, + RecordData &Record, + StringRef Blob, + bool allowEmptyString = false); + + LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags, + const char *&RetStr, + llvm::StringRef errorContext, + RecordData &Record, + StringRef Blob, + bool allowEmptyString = false); + + LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned RecStartIdx, + CXSourceRange &SR); + + LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned &offset, + CXLoadedDiagnostic::Location &Loc); + public: DiagLoader(enum CXLoadDiag_Error *e, CXString *es) - : SerializedDiagnosticReader(), error(e), errorString(es) { - if (error) - *error = CXLoadDiag_None; - if (errorString) - *errorString = cxstring::createEmpty(); - } + : error(e), errorString(es) { + if (error) + *error = CXLoadDiag_None; + if (errorString) + *errorString = cxstring::createEmpty(); + } CXDiagnosticSet load(const char *file); }; } CXDiagnosticSet DiagLoader::load(const char *file) { - TopDiags = llvm::make_unique<CXLoadedDiagnosticSetImpl>(); - - std::error_code EC = readDiagnostics(file); - if (EC) { - switch (EC.value()) { - case static_cast<int>(serialized_diags::SDError::HandlerFailed): - // We've already reported the problem. - break; - case static_cast<int>(serialized_diags::SDError::CouldNotLoad): - reportBad(CXLoadDiag_CannotLoad, EC.message()); - break; - default: - reportInvalidFile(EC.message()); - break; - } - return 0; + // Open the diagnostics file. + std::string ErrStr; + FileSystemOptions FO; + FileManager FileMgr(FO); + + std::unique_ptr<llvm::MemoryBuffer> Buffer = FileMgr.getBufferForFile(file); + if (!Buffer) { + reportBad(CXLoadDiag_CannotLoad, ErrStr); + return nullptr; } - return (CXDiagnosticSet)TopDiags.release(); -} + llvm::BitstreamReader StreamFile; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + + llvm::BitstreamCursor Stream; + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'D' || + Stream.Read(8) != 'I' || + Stream.Read(8) != 'A' || + Stream.Read(8) != 'G') { + reportBad(CXLoadDiag_InvalidFile, + "Bad header in diagnostics file"); + return nullptr; + } -std::error_code -DiagLoader::readLocation(const serialized_diags::Location &SDLoc, - CXLoadedDiagnostic::Location &LoadedLoc) { - unsigned FileID = SDLoc.FileID; - if (FileID == 0) - LoadedLoc.file = nullptr; - else { - LoadedLoc.file = const_cast<FileEntry *>(TopDiags->Files[FileID]); - if (!LoadedLoc.file) - return reportInvalidFile("Corrupted file entry in source location"); + std::unique_ptr<CXLoadedDiagnosticSetImpl> Diags( + new CXLoadedDiagnosticSetImpl()); + + while (true) { + unsigned BlockID = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level", + BlockID, true); + switch (Res) { + case Read_EndOfStream: + return (CXDiagnosticSet)Diags.release(); + case Read_Failure: + return nullptr; + case Read_Record: + llvm_unreachable("Top-level does not have records"); + case Read_BlockEnd: + continue; + case Read_BlockBegin: + break; + } + + switch (BlockID) { + case serialized_diags::BLOCK_META: + if (readMetaBlock(Stream)) + return nullptr; + break; + case serialized_diags::BLOCK_DIAG: + if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get())) + return nullptr; + break; + default: + if (!Stream.SkipBlock()) { + reportInvalidFile("Malformed block at top-level of diagnostics file"); + return nullptr; + } + break; + } } - LoadedLoc.line = SDLoc.Line; - LoadedLoc.column = SDLoc.Col; - LoadedLoc.offset = SDLoc.Offset; - return std::error_code(); } -std::error_code -DiagLoader::readRange(const serialized_diags::Location &SDStart, - const serialized_diags::Location &SDEnd, - CXSourceRange &SR) { - CXLoadedDiagnostic::Location *Start, *End; - Start = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>(); - End = TopDiags->Alloc.Allocate<CXLoadedDiagnostic::Location>(); - - std::error_code EC; - if ((EC = readLocation(SDStart, *Start))) - return EC; - if ((EC = readLocation(SDEnd, *End))) - return EC; +StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream, + llvm::StringRef errorContext, + unsigned &blockOrRecordID, + bool atTopLevel) { - CXSourceLocation startLoc = makeLocation(Start); - CXSourceLocation endLoc = makeLocation(End); - SR = clang_getRange(startLoc, endLoc); - return std::error_code(); + blockOrRecordID = 0; + + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + // Handle the top-level specially. + if (atTopLevel) { + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) { + if (Stream.ReadBlockInfoBlock()) { + reportInvalidFile("Malformed BlockInfoBlock in diagnostics file"); + return Read_Failure; + } + continue; + } + blockOrRecordID = BlockID; + return Read_BlockBegin; + } + reportInvalidFile("Only blocks can appear at the top of a " + "diagnostic file"); + return Read_Failure; + } + + switch ((llvm::bitc::FixedAbbrevIDs)Code) { + case llvm::bitc::ENTER_SUBBLOCK: + blockOrRecordID = Stream.ReadSubBlockID(); + return Read_BlockBegin; + + case llvm::bitc::END_BLOCK: + if (Stream.ReadBlockEnd()) { + reportInvalidFile("Cannot read end of block"); + return Read_Failure; + } + return Read_BlockEnd; + + case llvm::bitc::DEFINE_ABBREV: + Stream.ReadAbbrevRecord(); + continue; + + case llvm::bitc::UNABBREV_RECORD: + reportInvalidFile("Diagnostics file should have no unabbreviated " + "records"); + return Read_Failure; + + default: + // We found a record. + blockOrRecordID = Code; + return Read_Record; + } + } + + if (atTopLevel) + return Read_EndOfStream; + + reportInvalidFile(Twine("Premature end of diagnostics file within ").str() + + errorContext.str()); + return Read_Failure; } -std::error_code DiagLoader::visitStartOfDiagnostic() { - CurrentDiags.push_back(llvm::make_unique<CXLoadedDiagnostic>()); - return std::error_code(); -} +LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) { + if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) { + reportInvalidFile("Malformed metadata block"); + return Failure; + } -std::error_code DiagLoader::visitEndOfDiagnostic() { - auto D = CurrentDiags.pop_back_val(); - if (CurrentDiags.empty()) - TopDiags->appendDiagnostic(std::move(D)); - else - CurrentDiags.back()->getChildDiagnostics().appendDiagnostic(std::move(D)); - return std::error_code(); + bool versionChecked = false; + + while (true) { + unsigned blockOrCode = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block", + blockOrCode); + + switch(Res) { + case Read_EndOfStream: + llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock"); + case Read_Failure: + return Failure; + case Read_Record: + break; + case Read_BlockBegin: + if (Stream.SkipBlock()) { + reportInvalidFile("Malformed metadata block"); + return Failure; + } + case Read_BlockEnd: + if (!versionChecked) { + reportInvalidFile("Diagnostics file does not contain version" + " information"); + return Failure; + } + return Success; + } + + RecordData Record; + unsigned recordID = Stream.readRecord(blockOrCode, Record); + + if (recordID == serialized_diags::RECORD_VERSION) { + if (Record.size() < 1) { + reportInvalidFile("malformed VERSION identifier in diagnostics file"); + return Failure; + } + if (Record[0] > MaxSupportedVersion) { + reportInvalidFile("diagnostics file is a newer version than the one " + "supported"); + return Failure; + } + versionChecked = true; + } + } } -std::error_code DiagLoader::visitCategoryRecord(unsigned ID, StringRef Name) { - // FIXME: Why do we care about long strings? - if (Name.size() > 65536) - return reportInvalidFile("Out-of-bounds string in category"); - TopDiags->Categories[ID] = TopDiags->copyString(Name); - return std::error_code(); -} +LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags, + const char *&RetStr, + llvm::StringRef errorContext, + RecordData &Record, + StringRef Blob, + bool allowEmptyString) { + + // Basic buffer overflow check. + if (Blob.size() > 65536) { + reportInvalidFile(std::string("Out-of-bounds string in ") + + std::string(errorContext)); + return Failure; + } -std::error_code DiagLoader::visitDiagFlagRecord(unsigned ID, StringRef Name) { - // FIXME: Why do we care about long strings? - if (Name.size() > 65536) - return reportInvalidFile("Out-of-bounds string in warning flag"); - TopDiags->WarningFlags[ID] = TopDiags->copyString(Name); - return std::error_code(); + if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) { + RetStr = ""; + return Success; + } + + if (Record.size() < 1 || Blob.size() == 0) { + reportInvalidFile(std::string("Corrupted ") + std::string(errorContext) + + std::string(" entry")); + return Failure; + } + + RetStr = TopDiags.copyString(Blob); + return Success; } -std::error_code DiagLoader::visitFilenameRecord(unsigned ID, unsigned Size, - unsigned Timestamp, - StringRef Name) { - // FIXME: Why do we care about long strings? - if (Name.size() > 65536) - return reportInvalidFile("Out-of-bounds string in filename"); - TopDiags->FileNames[ID] = TopDiags->copyString(Name); - TopDiags->Files[ID] = - TopDiags->FakeFiles.getVirtualFile(Name, Size, Timestamp); - return std::error_code(); +LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags, + Strings &strings, + llvm::StringRef errorContext, + RecordData &Record, + StringRef Blob, + bool allowEmptyString) { + const char *RetStr; + if (readString(TopDiags, RetStr, errorContext, Record, Blob, + allowEmptyString)) + return Failure; + strings[Record[0]] = RetStr; + return Success; } -std::error_code -DiagLoader::visitSourceRangeRecord(const serialized_diags::Location &Start, - const serialized_diags::Location &End) { - CXSourceRange SR; - if (std::error_code EC = readRange(Start, End, SR)) - return EC; - CurrentDiags.back()->Ranges.push_back(SR); - return std::error_code(); +LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, unsigned &offset, + CXLoadedDiagnostic::Location &Loc) { + if (Record.size() < offset + 4) { + reportInvalidFile("Corrupted source location"); + return Failure; + } + auto Fields = makeArrayRef(Record).slice(offset); + offset += 4; + + unsigned fileID = Fields[0]; + if (fileID == 0) { + // Sentinel value. + Loc.file = nullptr; + Loc.line = 0; + Loc.column = 0; + Loc.offset = 0; + return Success; + } + + const FileEntry *FE = TopDiags.Files[fileID]; + if (!FE) { + reportInvalidFile("Corrupted file entry in source location"); + return Failure; + } + Loc.file = const_cast<FileEntry *>(FE); + Loc.line = Fields[1]; + Loc.column = Fields[2]; + Loc.offset = Fields[3]; + return Success; } -std::error_code -DiagLoader::visitFixitRecord(const serialized_diags::Location &Start, - const serialized_diags::Location &End, - StringRef CodeToInsert) { - CXSourceRange SR; - if (std::error_code EC = readRange(Start, End, SR)) - return EC; - // FIXME: Why do we care about long strings? - if (CodeToInsert.size() > 65536) - return reportInvalidFile("Out-of-bounds string in FIXIT"); - CurrentDiags.back()->FixIts.push_back( - std::make_pair(SR, TopDiags->copyString(CodeToInsert))); - return std::error_code(); +LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags, + RecordData &Record, + unsigned int RecStartIdx, + CXSourceRange &SR) { + CXLoadedDiagnostic::Location *Start, *End; + Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>(); + End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>(); + + if (readLocation(TopDiags, Record, RecStartIdx, *Start)) + return Failure; + if (readLocation(TopDiags, Record, RecStartIdx, *End)) + return Failure; + + CXSourceLocation startLoc = makeLocation(Start); + CXSourceLocation endLoc = makeLocation(End); + SR = clang_getRange(startLoc, endLoc); + return Success; } -std::error_code DiagLoader::visitDiagnosticRecord( - unsigned Severity, const serialized_diags::Location &Location, - unsigned Category, unsigned Flag, StringRef Message) { - CXLoadedDiagnostic &D = *CurrentDiags.back(); - D.severity = Severity; - if (std::error_code EC = readLocation(Location, D.DiagLoc)) - return EC; - D.category = Category; - D.DiagOption = Flag ? TopDiags->WarningFlags[Flag] : ""; - D.CategoryText = Category ? TopDiags->Categories[Category] : ""; - D.Spelling = TopDiags->copyString(Message); - return std::error_code(); +LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream, + CXDiagnosticSetImpl &Diags, + CXLoadedDiagnosticSetImpl &TopDiags){ + + if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) { + reportInvalidFile("malformed diagnostic block"); + return Failure; + } + + std::unique_ptr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic()); + RecordData Record; + + while (true) { + unsigned blockOrCode = 0; + StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block", + blockOrCode); + switch (Res) { + case Read_EndOfStream: + llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock"); + case Read_Failure: + return Failure; + case Read_BlockBegin: { + // The only blocks we care about are subdiagnostics. + if (blockOrCode != serialized_diags::BLOCK_DIAG) { + if (!Stream.SkipBlock()) { + reportInvalidFile("Invalid subblock in Diagnostics block"); + return Failure; + } + } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(), + TopDiags)) { + return Failure; + } + + continue; + } + case Read_BlockEnd: + Diags.appendDiagnostic(std::move(D)); + return Success; + case Read_Record: + break; + } + + // Read the record. + Record.clear(); + StringRef Blob; + unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob); + + if (recID < serialized_diags::RECORD_FIRST || + recID > serialized_diags::RECORD_LAST) + continue; + + switch ((serialized_diags::RecordIDs)recID) { + case serialized_diags::RECORD_VERSION: + continue; + case serialized_diags::RECORD_CATEGORY: + if (readString(TopDiags, TopDiags.Categories, "category", Record, + Blob, /* allowEmptyString */ true)) + return Failure; + continue; + + case serialized_diags::RECORD_DIAG_FLAG: + if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record, + Blob)) + return Failure; + continue; + + case serialized_diags::RECORD_FILENAME: { + if (readString(TopDiags, TopDiags.FileNames, "filename", Record, + Blob)) + return Failure; + + if (Record.size() < 3) { + reportInvalidFile("Invalid file entry"); + return Failure; + } + + const FileEntry *FE = + TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]], + /* size */ Record[1], + /* time */ Record[2]); + + TopDiags.Files[Record[0]] = FE; + continue; + } + + case serialized_diags::RECORD_SOURCE_RANGE: { + CXSourceRange SR; + if (readRange(TopDiags, Record, 0, SR)) + return Failure; + D->Ranges.push_back(SR); + continue; + } + + case serialized_diags::RECORD_FIXIT: { + CXSourceRange SR; + if (readRange(TopDiags, Record, 0, SR)) + return Failure; + const char *RetStr; + if (readString(TopDiags, RetStr, "FIXIT", Record, Blob, + /* allowEmptyString */ true)) + return Failure; + D->FixIts.push_back(std::make_pair(SR, RetStr)); + continue; + } + + case serialized_diags::RECORD_DIAG: { + D->severity = Record[0]; + unsigned offset = 1; + if (readLocation(TopDiags, Record, offset, D->DiagLoc)) + return Failure; + D->category = Record[offset++]; + unsigned diagFlag = Record[offset++]; + D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : ""; + D->CategoryText = D->category ? TopDiags.Categories[D->category] : ""; + D->Spelling = TopDiags.copyString(Blob); + continue; + } + } + } } extern "C" { |