[cfe-dev] Clang 3.2 assertion failure writing AST files: RecordIdx == Vals.size() && "Not all record operands emitted!"
Argyrios Kyrtzidis
akyrtzi at gmail.com
Mon Mar 18 15:26:00 PDT 2013
Fixed in r177330, thanks for the report and the investigation!
-Argyrios
On Feb 26, 2013, at 7:16 PM, Tom Honermann <thonermann at coverity.com> wrote:
> The following code causes Clang (3.2 on Linux) to fail an assertion test when serializing an AST to an AST file.
>
> template<typename T>
> void f() {
> enum E {
> enumerator
> };
>
> T t = enumerator;
> }
>
> template void f<int>();
>
> $ clang -c t.cpp
> <no error, object file is generated successfully>
>
> $ clang -emit-ast t.cpp
> clang: /nfs/thonermann/clang-3.2/llvm-3.2/include/llvm/Bitcode/BitstreamWriter.h:398: void llvm::BitstreamWriter::EmitRecordWithAbbrevImpl(unsigned int, llvm::SmallVectorImpl<T>&, llvm::StringRef) [with uintty = long unsigned int]: Assertion `RecordIdx == Vals.size() && "Not all record operands emitted!"' failed.
> clang: error: unable to execute command: Segmentation fault (core dumped)
> clang: error: clang frontend command failed due to signal (use -v to see invocation)
> clang version 3.2 (tags/RELEASE_32/final)
> Target: x86_64-unknown-linux-gnu
> Thread model: posix
> clang: note: diagnostic msg: PLEASE submit a bug report to http://llvm.org/bugs/ and include the crash backtrace, preprocessed source, and associated run script.
> clang: note: diagnostic msg:
> ********************
>
> PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
> Preprocessed source(s) and associated run script(s) are located at:
> clang: note: diagnostic msg: /tmp/t-dqKSIG.cpp
> clang: note: diagnostic msg: /tmp/t-dqKSIG.sh
> clang: note: diagnostic msg:
>
> ********************
>
> /tmp/t-dqKSIG.cpp contains the sample code above.
> /tmp/t-dqKSIG.sh contains:
> /path/to/clang -cc1 -triple x86_64-unknown-linux-gnu -emit-pch -disable-free -main-file-name t.cpp -mrelocation-model static -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-linker-version 2.22 -momit-leaf-frame-pointer -fdeprecated-macro -ferror-limit 19 -fmessage-length 197 -mstackrealign -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -x c++ t-dqKSIG.cpp
>
> This assertion failure (with a different test case) was previously reported here:
> http://llvm.org/bugs/show_bug.cgi?id=13020
> Bug 13020 - Clang 3.1 assertion failures reading and writing AST files
>
> The assertion failure occurs at line 398 below:
>
> include/llvm/Bitcode/BitstreamWriter.h:
> 25 class BitstreamWriter {
> ...
> 313 template<typename uintty>
> 314 void EmitRecordWithAbbrevImpl(unsigned Abbrev, SmallVectorImpl<uintty> &Vals,
> 315 StringRef Blob) {
> ...
> 398 assert(RecordIdx == Vals.size() && "Not all record operands emitted!");
> 399 assert(BlobData == 0 &&
> 400 "Blob data specified for record that doesn't use it!");
> 401 }
>
> The problem is that ASTDeclWriter::VisitEnumDecl() in lib/Serialization/ASTWriterDecl.cpp incorrectly determines that the abbreviated form of the EnumDecl bit stream can be used when serializing the enum member declaration of the f<int> specialization and ends up passing more operands than are expected for the abbreviation.
>
> The problematic code is here:
>
> lib/Serialization/ASTWriterDecl.cpp:
> 224 void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
> ...
> 235 if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
> 236 Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
> 237 Record.push_back(MemberInfo->getTemplateSpecializationKind());
> 238 Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
> 239 } else {
> 240 Writer.AddDeclRef(0, Record);
> 241 }
> 242
> 243 if (!D->hasAttrs() &&
> 244 !D->isImplicit() &&
> 245 !D->isUsed(false) &&
> 246 !D->hasExtInfo() &&
> 247 D->getFirstDeclaration() == D->getMostRecentDecl() &&
> 248 !D->isInvalidDecl() &&
> 249 !D->isReferenced() &&
> 250 !D->isTopLevelDeclInObjCContainer() &&
> 251 D->getAccess() == AS_none &&
> 252 !D->isModulePrivate() &&
> 253 !CXXRecordDecl::classofKind(D->getKind()) &&
> 254 !D->getIntegerTypeSourceInfo() &&
> 255 D->getDeclName().getNameKind() == DeclarationName::Identifier &&
> 256 !D->getMemberSpecializationInfo())
> 257 AbbrevToUse = Writer.getDeclEnumAbbrev();
> 258
> 259 Code = serialization::DECL_ENUM;
> 260 }
>
> Lines 235-241 will queue a conditional number of record operands depending on whether the declaration has member specialization info. The abbreviated bit stream expects just one (matching the else body). Adding a check for '!D->getMemberSpecializationInfo()' to the if conditions at lines 243-256 above appears to correct this problem:
>
> @@ -252,7 +252,8 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
> !D->isModulePrivate() &&
> !CXXRecordDecl::classofKind(D->getKind()) &&
> !D->getIntegerTypeSourceInfo() &&
> - D->getDeclName().getNameKind() == DeclarationName::Identifier)
> + D->getDeclName().getNameKind() == DeclarationName::Identifier &&
> + !D->getMemberSpecializationInfo())
> AbbrevToUse = Writer.getDeclEnumAbbrev();
>
> For reference, here is the corresponding code to build the enum declaration abbreviation that matches the else body at line 240 above.
>
> lib/Serialization/ASTWriterDecl.cpp:
> 1300 void ASTWriter::WriteDeclsBlockAbbrevs() {
> ....
> 1372 // Abbreviation for DECL_ENUM
> 1373 Abv = new BitCodeAbbrev();
> ....
> 1413 Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedMembEnum
> ....
> 1650 }
>
> Tom.
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130318/35b52856/attachment.html>
More information about the cfe-dev
mailing list