[cfe-dev] Clang 3.2 assertion failure writing AST files: RecordIdx == Vals.size() && "Not all record operands emitted!"
Tom Honermann
thonermann at coverity.com
Tue Feb 26 19:16:22 PST 2013
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.
More information about the cfe-dev
mailing list