From 1ff615ce4cc5decb0ac1aae826f66651d94f4982 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 18 Mar 2010 00:56:54 +0000 Subject: [PATCH] Turn several PCH reader assertions into compiler errors, thus making the PCHReader more robust to corrupt or invalid PCH files. llvm-svn: 98788 --- .../clang/Basic/DiagnosticFrontendKinds.td | 6 +- clang/include/clang/Frontend/PCHReader.h | 11 +- clang/lib/Frontend/PCHReader.cpp | 124 +++++++++++++----- 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index e6a9f673d7e6..3a28282d5522 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -51,10 +51,12 @@ def err_fe_unable_to_read_pch_file : Error< "unable to read PCH file: '%0'">; def err_fe_not_a_pch_file : Error< "input is not a PCH file: '%0'">; +def err_fe_pch_malformed : Error< + "malformed or corrupted PCH file: '%0'">, DefaultFatal; def err_fe_pch_malformed_block : Error< - "malformed block record in PCH file: '%0'">; + "malformed block record in PCH file: '%0'">, DefaultFatal; def err_fe_pch_error_at_end_block : Error< - "error at end of module block in PCH file: '%0'">; + "error at end of module block in PCH file: '%0'">, DefaultFatal; def err_fe_unable_to_open_output : Error< "unable to open output file '%0': '%1'">; def err_fe_unable_to_open_logfile : Error< diff --git a/clang/include/clang/Frontend/PCHReader.h b/clang/include/clang/Frontend/PCHReader.h index 7aafb2d5dee4..e4fd1a2b15af 100644 --- a/clang/include/clang/Frontend/PCHReader.h +++ b/clang/include/clang/Frontend/PCHReader.h @@ -132,6 +132,9 @@ public: std::string &SuggestedPredefines); virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID); virtual void ReadCounter(unsigned Value); + +private: + void Error(const char *Msg); }; /// \brief Reads a precompiled head containing the contents of a @@ -154,7 +157,7 @@ class PCHReader public ExternalSLocEntrySource { public: enum PCHReadResult { Success, Failure, IgnorePCH }; - + friend class PCHValidator; private: /// \ brief The receiver of some callbacks invoked by PCHReader. llvm::OwningPtr Listener; @@ -472,7 +475,7 @@ private: /// /// This routine should only be used for fatal errors that have to /// do with non-routine failures (e.g., corrupted PCH file). - bool Error(const char *Msg); + void Error(const char *Msg); PCHReader(const PCHReader&); // do not implement PCHReader &operator=(const PCHReader &); // do not implement @@ -790,6 +793,10 @@ private: uint64_t Offset; }; +inline void PCHValidator::Error(const char *Msg) { + Reader.Error(Msg); +} + } // end namespace clang #endif diff --git a/clang/lib/Frontend/PCHReader.cpp b/clang/lib/Frontend/PCHReader.cpp index f1c0247b814a..63146a2ee768 100644 --- a/clang/lib/Frontend/PCHReader.cpp +++ b/clang/lib/Frontend/PCHReader.cpp @@ -150,7 +150,10 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef, std::pair Split = llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); llvm::StringRef Left = Split.first, Right = Split.second; - assert(Left != PP.getPredefines() && "Missing PCH include entry!"); + if (Left == PP.getPredefines()) { + Error("Missing PCH include entry!"); + return true; + } // If the predefines is equal to the joined left and right halves, we're done! if (Left.size() + Right.size() == PCHPredef.size() && @@ -603,10 +606,8 @@ public: typedef OnDiskChainedHashTable PCHIdentifierLookupTable; -bool PCHReader::Error(const char *Msg) { - unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Fatal, Msg); - Diag(DiagID); - return true; +void PCHReader::Error(const char *Msg) { + Diag(diag::err_fe_pch_malformed) << Msg; } /// \brief Check the contents of the predefines buffer against the @@ -927,8 +928,12 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { Record.clear(); unsigned RecCode = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); - assert(RecCode == pch::SM_SLOC_BUFFER_BLOB && "Ill-formed PCH file"); - (void)RecCode; + + if (RecCode != pch::SM_SLOC_BUFFER_BLOB) { + Error("PCH record has invalid code"); + return Failure; + } + llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(BlobStart, BlobStart + BlobLen - 1, @@ -1583,29 +1588,44 @@ void PCHReader::InitializeContext(ASTContext &Ctx) { Context->setObjCFastEnumerationStateType(GetType(FastEnum)); if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) { QualType FileType = GetType(File); - assert(!FileType.isNull() && "FILE type is NULL"); + if (FileType.isNull()) { + Error("FILE type is NULL"); + return; + } if (const TypedefType *Typedef = FileType->getAs()) Context->setFILEDecl(Typedef->getDecl()); else { const TagType *Tag = FileType->getAs(); - assert(Tag && "Invalid FILE type in PCH file"); + if (!Tag) { + Error("Invalid FILE type in PCH file"); + return; + } Context->setFILEDecl(Tag->getDecl()); } } if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) { QualType Jmp_bufType = GetType(Jmp_buf); - assert(!Jmp_bufType.isNull() && "jmp_bug type is NULL"); + if (Jmp_bufType.isNull()) { + Error("jmp_bug type is NULL"); + return; + } if (const TypedefType *Typedef = Jmp_bufType->getAs()) Context->setjmp_bufDecl(Typedef->getDecl()); else { const TagType *Tag = Jmp_bufType->getAs(); - assert(Tag && "Invalid jmp_bug type in PCH file"); + if (!Tag) { + Error("Invalid jmp_bug type in PCH file"); + return; + } Context->setjmp_bufDecl(Tag->getDecl()); } } if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) { QualType Sigjmp_bufType = GetType(Sigjmp_buf); - assert(!Sigjmp_bufType.isNull() && "sigjmp_buf type is NULL"); + if (Sigjmp_bufType.isNull()) { + Error("sigjmp_buf type is NULL"); + return; + } if (const TypedefType *Typedef = Sigjmp_bufType->getAs()) Context->setsigjmp_bufDecl(Typedef->getDecl()); else { @@ -1822,45 +1842,65 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { unsigned Code = DeclsCursor.ReadCode(); switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { case pch::TYPE_EXT_QUAL: { - assert(Record.size() == 2 && - "Incorrect encoding of extended qualifier type"); + if (Record.size() != 2) { + Error("Incorrect encoding of extended qualifier type"); + return QualType(); + } QualType Base = GetType(Record[0]); Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); return Context->getQualifiedType(Base, Quals); } case pch::TYPE_COMPLEX: { - assert(Record.size() == 1 && "Incorrect encoding of complex type"); + if (Record.size() != 1) { + Error("Incorrect encoding of complex type"); + return QualType(); + } QualType ElemType = GetType(Record[0]); return Context->getComplexType(ElemType); } case pch::TYPE_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getPointerType(PointeeType); } case pch::TYPE_BLOCK_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of block pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of block pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getBlockPointerType(PointeeType); } case pch::TYPE_LVALUE_REFERENCE: { - assert(Record.size() == 1 && "Incorrect encoding of lvalue reference type"); + if (Record.size() != 1) { + Error("Incorrect encoding of lvalue reference type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getLValueReferenceType(PointeeType); } case pch::TYPE_RVALUE_REFERENCE: { - assert(Record.size() == 1 && "Incorrect encoding of rvalue reference type"); + if (Record.size() != 1) { + Error("Incorrect encoding of rvalue reference type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); return Context->getRValueReferenceType(PointeeType); } case pch::TYPE_MEMBER_POINTER: { - assert(Record.size() == 1 && "Incorrect encoding of member pointer type"); + if (Record.size() != 1) { + Error("Incorrect encoding of member pointer type"); + return QualType(); + } QualType PointeeType = GetType(Record[0]); QualType ClassType = GetType(Record[1]); return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr()); @@ -1956,7 +1996,10 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { cast(GetDecl(Record[0]))); case pch::TYPE_TYPEDEF: - assert(Record.size() == 1 && "incorrect encoding of typedef type"); + if (Record.size() != 1) { + Error("incorrect encoding of typedef type"); + return QualType(); + } return Context->getTypeDeclType(cast(GetDecl(Record[0]))); case pch::TYPE_TYPEOF_EXPR: @@ -1975,15 +2018,24 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { return Context->getDecltypeType(ReadTypeExpr()); case pch::TYPE_RECORD: - assert(Record.size() == 1 && "incorrect encoding of record type"); + if (Record.size() != 1) { + Error("incorrect encoding of record type"); + return QualType(); + } return Context->getTypeDeclType(cast(GetDecl(Record[0]))); case pch::TYPE_ENUM: - assert(Record.size() == 1 && "incorrect encoding of enum type"); + if (Record.size() != 1) { + Error("incorrect encoding of enum type"); + return QualType(); + } return Context->getTypeDeclType(cast(GetDecl(Record[0]))); case pch::TYPE_ELABORATED: { - assert(Record.size() == 2 && "incorrect encoding of elaborated type"); + if (Record.size() != 2) { + Error("incorrect encoding of elaborated type"); + return QualType(); + } unsigned Tag = Record[1]; return Context->getElaboratedType(GetType(Record[0]), (ElaboratedType::TagKind) Tag); @@ -2328,8 +2380,12 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, llvm::SmallVectorImpl &Decls) { assert(DC->hasExternalLexicalStorage() && "DeclContext has no lexical decls in storage"); + uint64_t Offset = DeclContextOffsets[DC].first; - assert(Offset && "DeclContext has no lexical decls in storage"); + if (Offset == 0) { + Error("DeclContext has no lexical decls in storage"); + return true; + } // Keep track of where we are in the stream, then jump back there // after reading this context. @@ -2341,8 +2397,10 @@ bool PCHReader::ReadDeclsLexicallyInContext(DeclContext *DC, RecordData Record; unsigned Code = DeclsCursor.ReadCode(); unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - (void)RecCode; - assert(RecCode == pch::DECL_CONTEXT_LEXICAL && "Expected lexical block"); + if (RecCode != pch::DECL_CONTEXT_LEXICAL) { + Error("Expected lexical block"); + return true; + } // Load all of the declaration IDs Decls.clear(); @@ -2356,7 +2414,10 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, assert(DC->hasExternalVisibleStorage() && "DeclContext has no visible decls in storage"); uint64_t Offset = DeclContextOffsets[DC].second; - assert(Offset && "DeclContext has no visible decls in storage"); + if (Offset == 0) { + Error("DeclContext has no visible decls in storage"); + return true; + } // Keep track of where we are in the stream, then jump back there // after reading this context. @@ -2368,8 +2429,11 @@ bool PCHReader::ReadDeclsVisibleInContext(DeclContext *DC, RecordData Record; unsigned Code = DeclsCursor.ReadCode(); unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - (void)RecCode; - assert(RecCode == pch::DECL_CONTEXT_VISIBLE && "Expected visible block"); + if (RecCode != pch::DECL_CONTEXT_VISIBLE) { + Error("Expected visible block"); + return true; + } + if (Record.size() == 0) return false;