[clang][CodeGen] ICE: dllexporting a class that inherits a constructor with an incomplete-type parameter
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Summary
Clang crashes (access violation, `0xC0000005`) during LLVM IR generation when a `__declspec(dllexport)` class inherits a base-class constructor (`using Base::Base;`) whose parameter is an **incomplete** class type passed by value.
I have encountered this in clang-cl.exe, but it's not specific to `clang-cl` or the MS C++ ABI. it reproduces with the plain `clang` driver on any Windows target, both `x86_64-pc-windows-msvc` and `x86_64-pc-windows-gnu`.
The null dereference happens in `clang::ASTContext::getASTRecordLayout`
## Environment
- Compiler: [clang version 23.1.0](https://github.com/llvm/llvm-project/releases/tag/llvmorg-23.1.0)
- Reproduces with `clang`, `clang++`, and `clang-cl` drivers, and directly via `-cc1`.
- Language: default standard is enough (needs C++11 for inherited constructors)
## Minimal repro
Original repro minimized via `cvise` and a bit of hand-editing:
```cpp
class Incomplete;
struct Base { Base(Incomplete); };
struct __declspec(dllexport) Derived : Base {
using Base::Base;
};
```
Commands (any one of these):
```sh
# simplest: MSVC target and -fdeclspec implied
clang-cl -c crash-min.cpp
# plain clang driver, Itanium ABI (MinGW target)
clang --target=x86_64-pc-windows-gnu -fdeclspec -c crash-min.cpp -o crash-min.o
# frontend only, fastest (crash is in IRGen, before the backend)
clang -cc1 -triple x86_64-pc-windows-gnu -fdeclspec -emit-llvm-only crash-min.cpp
```
Any one of the following avoids the crash:
* making the ctor parameter a complete type
* dropping `__declspec(dllexport)` on `Derived`
* replacing `using Base::Base;` with a user-declared ctor
* non-Windows target
## Stack
```
Exception Code: 0xC0000005
#0 0x00007ff7d5665bed clang::Decl::getKind C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\AST\DeclBase.h:1937:0
#1 0x00007ff7d5665bed clang::CXXRecordDecl::classof C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\AST\DeclCXX.h:1935:0
#2 0x00007ff7d5665bed llvm::isa_impl::doit C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:64:0
#3 0x00007ff7d5665bed llvm::isa_impl_cl::doit C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:110:0
#4 0x00007ff7d5665bed llvm::isa_impl_wrap::doit C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:137:0
#5 0x00007ff7d5665bed llvm::isa_impl_wrap::doit C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:127:0
#6 0x00007ff7d5665bed llvm::CastIsPossible::isPossible C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:255:0
#7 0x00007ff7d5665bed llvm::CastInfo::doCastIfPossible C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:493:0
#8 0x00007ff7d5665bed llvm::dyn_cast C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Casting.h:657:0
#9 0x00007ff7d5665bed clang::ASTContext::getASTRecordLayout(class clang::RecordDecl const *) const C:\S\llvm-e9988a0e4bbdf\p\clang\lib\AST\RecordLayoutBuilder.cpp:0:0
#10 0x00007ff7d689a63d clang::ASTContext::getTypeInfoImpl C:\S\llvm-e9988a0e4bbdf\p\clang\lib\AST\ASTContext.cpp:2213:0
#11 0x00007ff7d5641391 llvm::DenseMap,llvm::detail::DenseMapPair >::getRep C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\DenseMap.h:905:0
#12 0x00007ff7d5641391 llvm::DenseMapBase,llvm::detail::DenseMapPair >,const clang::Type *,clang::TypeInfo,llvm::DenseMapInfo,llvm::detail::DenseMapPair >::getRep C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\DenseMap.h:672:0
#13 0x00007ff7d5641391 llvm::DenseMapBase,llvm::detail::DenseMapPair >,const clang::Type *,clang::TypeInfo,llvm::DenseMapInfo,llvm::detail::DenseMapPair >::LookupBucketFor C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\DenseMap.h:753:0
#14 0x00007ff7d5641391 llvm::DenseMapBase,llvm::detail::DenseMapPair >,const clang::Type *,clang::TypeInfo,llvm::DenseMapInfo,llvm::detail::DenseMapPair >::lookupOrInsertIntoBucket C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\DenseMap.h:633:0
#15 0x00007ff7d5641391 llvm::DenseMapBase,llvm::detail::DenseMapPair >,const clang::Type *,clang::TypeInfo,llvm::DenseMapInfo,llvm::detail::DenseMapPair >::operator[] C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\DenseMap.h:417:0
#16 0x00007ff7d5641391 clang::ASTContext::getTypeInfo(class clang::Type const *) const C:\S\llvm-e9988a0e4bbdf\p\clang\lib\AST\ASTContext.cpp:2099:0
#17 0x00007ff7d8388400 `anonymous namespace'::WinX86_64ABIInfo::classify C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\Targets\X86.cpp:3416:0
#18 0x00007ff7d720dd52 `anonymous namespace'::WinX86_64ABIInfo::computeInfo C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\Targets\X86.cpp:3602:0
#19 0x00007ff7d82f8c2f clang::CodeGen::ABIArgInfo::isDirect C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\CodeGen\CGFunctionInfo.h:319:0
#20 0x00007ff7d82f8c2f clang::CodeGen::ABIArgInfo::canHaveCoerceToType C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\CodeGen\CGFunctionInfo.h:330:0
#21 0x00007ff7d82f8c2f clang::CodeGen::CodeGenTypes::arrangeLLVMFunctionInfo(class clang::CanQual, enum clang::CodeGen::FnInfoOpts, class llvm::ArrayRef>, class clang::FunctionType::ExtInfo, class llvm::ArrayRef, class clang::CodeGen::RequiredArgs) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CGCall.cpp:1074:0
#22 0x00007ff7d57782c0 clang::CodeGen::CodeGenTypes::arrangeCXXStructorDeclaration(class clang::GlobalDecl) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CGCall.cpp:454:0
#23 0x00007ff7d5829756 clang::CodeGen::CodeGenModule::codegenCXXStructor(class clang::GlobalDecl) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CGCXX.cpp:267:0
#24 0x00007ff7d5829489 `anonymous namespace'::MicrosoftCXXABI::emitCXXStructor C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\MicrosoftCXXABI.cpp:4092:0
#25 0x00007ff7d83adb62 clang::CodeGen::CodeGenModule::EmitGlobalDefinition C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CodeGenModule.cpp:4993:0
#26 0x00007ff7d58f3a6c clang::CodeGen::CodeGenModule::addEmittedDeferredDecl C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CodeGenModule.h:435:0
#27 0x00007ff7d58f3a6c clang::CodeGen::CodeGenModule::EmitGlobal(class clang::GlobalDecl) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CodeGenModule.cpp:4770:0
#28 0x00007ff7d8477c9a clang::Decl::hasAttrs C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\AST\DeclBase.h:526:0
#29 0x00007ff7d8477c9a clang::Decl::hasAttr C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\AST\DeclBase.h:586:0
#30 0x00007ff7d8477c9a `anonymous namespace'::MicrosoftCXXABI::EmitCXXConstructors C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\MicrosoftCXXABI.cpp:1331:0
#31 0x00007ff7d832d5e8 `anonymous namespace'::CodeGeneratorImpl::HandleTagDeclDefinition C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\ModuleBuilder.cpp:280:0
#32 0x00007ff7d832d5e8 clang::BackendConsumer::HandleTagDeclDefinition C:\S\llvm-e9988a0e4bbdf\p\clang\lib\CodeGen\CodeGenAction.cpp:334:0
#33 0x00007ff7d56d25e1 clang::Sema::ActOnTagFinishDefinition(class clang::Scope *, class clang::Decl *, class clang::SourceRange) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Sema\SemaDecl.cpp:19219:0
#34 0x00007ff7d809452c clang::Parser::ParsingClassDefinition::Pop C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Parse\Parser.h:2940:0
#35 0x00007ff7d809452c clang::Parser::ParseCXXMemberSpecification C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDeclCXX.cpp:3744:0
#36 0x00007ff7d8092829 clang::Parser::ParseClassSpecifier(enum clang::tok::TokenKind, class clang::SourceLocation, class clang::DeclSpec &, struct clang::Parser::ParsedTemplateInfo &, enum clang::AccessSpecifier, bool, enum clang::Parser::DeclSpecContext, class clang::ParsedAttributes &) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDeclCXX.cpp:2179:0
#37 0x00007ff7d57c2d75 llvm::SmallVectorBase::empty C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\ADT\SmallVector.h:86:0
#38 0x00007ff7d57c2d75 clang::ParsedAttributesView::empty C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Sema\ParsedAttr.h:822:0
#39 0x00007ff7d57c2d75 clang::Parser::ParseDeclarationSpecifiers(class clang::DeclSpec &, struct clang::Parser::ParsedTemplateInfo &, enum clang::AccessSpecifier, enum clang::Parser::DeclSpecContext, class clang::LateParsedAttrList *, enum clang::ImplicitTypenameContext) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDecl.cpp:4517:0
#40 0x00007ff7d58525bd clang::Parser::ParseDeclOrFunctionDefInternal C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\Parser.cpp:1067:0
#41 0x00007ff7d842f668 llvm::SaveAndRestore::~SaveAndRestore C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\SaveAndRestore.h:29:0
#42 0x00007ff7d842f668 clang::Parser::ObjCDeclContextSwitch::~ObjCDeclContextSwitch C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Parse\Parser.h:5475:0
#43 0x00007ff7d842f668 clang::Parser::ParseDeclarationOrFunctionDefinition(class clang::ParsedAttributes &, class clang::ParsedAttributes &, class clang::ParsingDeclSpec *, enum clang::AccessSpecifier) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\Parser.cpp:1176:0
#44 0x00007ff7d599a892 clang::Parser::ParseExternalDeclaration(class clang::ParsedAttributes &, class clang::ParsedAttributes &, class clang::ParsingDeclSpec *) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\Parser.cpp:1003:0
#45 0x00007ff7d84a4524 clang::AttributePool::~AttributePool C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Sema\ParsedAttr.h:709:0
#46 0x00007ff7d84a4524 clang::ParsedAttributes::~ParsedAttributes C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Sema\ParsedAttr.h:937:0
#47 0x00007ff7d84a4524 clang::Parser::ParseInnerNamespace C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDeclCXX.cpp:237:0
#48 0x00007ff7d84a463d clang::Parser::ParseScope::Exit C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Parse\Parser.h:518:0
#49 0x00007ff7d84a463d clang::Parser::ParseInnerNamespace C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDeclCXX.cpp:260:0
#50 0x00007ff7d59b364d clang::Parser::ParseScope::Exit C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Parse\Parser.h:518:0
#51 0x00007ff7d59b364d clang::Parser::ParseNamespace(enum clang::DeclaratorContext, class clang::SourceLocation &, class clang::SourceLocation) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDeclCXX.cpp:217:0
#52 0x00007ff7d84a7840 clang::Parser::ParseDeclaration(enum clang::DeclaratorContext, class clang::SourceLocation &, class clang::ParsedAttributes &, class clang::ParsedAttributes &, class clang::SourceLocation *) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseDecl.cpp:1935:0
#53 0x00007ff7d599a1f6 clang::SourceLocation::SourceLocation C:\S\llvm-e9988a0e4bbdf\p\clang\include\clang\Basic\SourceLocation.h:59:0
#54 0x00007ff7d599a1f6 clang::Parser::ParseExternalDeclaration(class clang::ParsedAttributes &, class clang::ParsedAttributes &, class clang::ParsingDeclSpec *) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\Parser.cpp:0:0
#55 0x00007ff7d5c889d1 clang::Parser::ParseTopLevelDecl(class clang::OpaquePtr &, enum clang::Sema::ModuleImportState &) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\Parser.cpp:711:0
#56 0x00007ff7d76f80a3 clang::ParseAST(class clang::Sema &, bool, bool) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Parse\ParseAST.cpp:169:0
#57 0x00007ff7d6a827f3 clang::FrontendAction::Execute(void) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Frontend\FrontendAction.cpp:1348:0
#58 0x00007ff7d5ccb0f7 llvm::Error::getPtr C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Error.h:281:0
#59 0x00007ff7d5ccb0f7 llvm::Error::operator bool C:\S\llvm-e9988a0e4bbdf\p\llvm\include\llvm\Support\Error.h:241:0
#60 0x00007ff7d5ccb0f7 clang::CompilerInstance::ExecuteAction(class clang::FrontendAction &) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\Frontend\CompilerInstance.cpp:1033:0
#61 0x00007ff7d5cca00d clang::ExecuteCompilerInvocation(class clang::CompilerInstance *) C:\S\llvm-e9988a0e4bbdf\p\clang\lib\FrontendTool\ExecuteCompilerInvocation.cpp:319:0
#62 0x00007ff7d5c1d32b cc1_main(class llvm::ArrayRef, char const *, void *) C:\S\llvm-e9988a0e4bbdf\p\clang\tools\driver\cc1_main.cpp:296:0
#63 0x00007ff7d5c1c6df ExecuteCC1Tool(class llvm::SmallVectorImpl &, struct llvm::ToolContext const &, class llvm::IntrusiveRefCntPtr) C:\S\llvm-e9988a0e4bbdf\p\clang\tools\driver\driver.cpp:229:0
#64 0x00007ff7d5c54bbf clang_main(int, char **, struct llvm::ToolContext const &) C:\S\llvm-e9988a0e4bbdf\p\clang\tools\driver\driver.cpp:277:0
#65 0x00007ff7d5c53828 main C:\S\b\clang85748b1fd1bb4\b\tools\clang\tools\driver\clang-driver.cpp:17:0
#66 0x00007ff7d85b8ae4 invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78:0
#67 0x00007ff7d85b8ae4 __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288:0
#68 0x00007ffd67bf7ac4 (C:\Windows\System32\KERNEL32.DLL+0x17ac4)
#69 0x00007ffd68b8a8c1 (C:\Windows\SYSTEM32\ntdll.dll+0x5a8c1)
```
## Original context
This is the real snippet that triggered the crash, a `NX_UTILS_API` (`__declspec(dllexport)`) class deriving from Qt's `QDataStream` and inheriting its constructors:
```cpp
class NX_UTILS_API DataStream: public QDataStream {
using base_type = QDataStream;
public:
using base_type::base_type; // inherits QDataStream(QIODevice*), QDataStream(QByteArray*, OpenMode), ...
DataStream(std::string_view buf);
};
```
Original crashing translation unit and the exact driver/`-cc1` command line are in the attached original repro dump (`data_stream-7a60a9.cpp` preprocessed source, `data_stream-7a60a9.sh` the clang-generated reproducer script).
Downstream workaround: move the export from the class to the single user-declared constructor, so the class is not force-exported and the inherited constructors are not emitted:
```cpp
class DataStream: public QDataStream {
using base_type = QDataStream;
public:
using base_type::base_type;
NX_UTILS_API DataStream(std::string_view buf); // export the member, not the class
};
```
[data_stream-7a60a9.sh](https://github.com/user-attachments/files/31554072/data_stream-7a60a9.sh)
[data_stream-7a60a9.cpp](https://github.com/user-attachments/files/31554076/data_stream-7a60a9.cpp)
Contributor guide
Research direction
Reproduce the crash with the minimal C++ example using the listed clang or clang -cc1 command. Start at clang::ASTContext::getASTRecordLayout and follow the stack through WinX86_64ABIInfo::classify and CodeGenTypes::arrangeCXXStructorDeclaration. Done means the incomplete-type inherited-constructor case no longer crashes on the affected Windows targets and has regression coverage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100