llvm / llvm/llvm-project

[Clang][Modules] Crash in ASTContext::getCanonicalTagType during lazy deserialization on namespace reopen

Open
#188,906 1 comment 0 reactions 0 assignees View on GitHub
clang:modules crash
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Description

Clang crashes in `ASTContext::getCanonicalTagType()` during lazy deserialization of declarations from a precompiled module (PCM). The crash is triggered when a translation unit imports a module and then re-opens a namespace used within that module.

## Trigger pattern

```cpp
import strongai.type.tagged_union; // module with deep template instantiation chain

namespace StrongAI {
int x = 0; // re-opening the namespace triggers lazy deserialization -> crash
}
```

## Crash path

1. Parser encounters `namespace StrongAI {` -> `ActOnStartNamespaceDef`
2. Qualified lookup triggers `FindExternalVisibleDeclsByName`
3. `ASTReader` begins lazy deserialization: `FinishedDeserializing` -> `finishPendingActions` -> `loadDeclUpdateRecords` -> `UpdateDecl`
4. While reading a template argument list, `readTypeRecord` needs a canonical type
5. `ASTContext::getCanonicalTagType` follows a corrupted/stale `TagDecl*` and crashes (recursive call visible in trace)

## Stack trace

```
#5 clang::ASTContext::getCanonicalTagType(clang::TagDecl const*) const
#6 clang::ASTContext::getCanonicalTagType(clang::TagDecl const*) const
#7 clang::ASTReader::readTypeRecord(unsigned long long)
#8 clang::ASTReader::GetType(unsigned long long)
#9 clang::serialization::BasicReaderBase::readTemplateArgument()
#10 clang::ASTRecordReader::readTemplateArgumentList(...)
#11 clang::ASTDeclReader::UpdateDecl(clang::Decl*)
#12 clang::ASTReader::loadDeclUpdateRecords(...)
#13 clang::ASTReader::finishPendingActions()
#14 clang::ASTReader::FinishedDeserializing()
#15 clang::ASTReader::FindExternalVisibleDeclsByName(...)
#16 clang::DeclContext::lookupImpl(...)
#17 LookupDirect(...)
#18 clang::Sema::LookupQualifiedName(...)
#19 clang::Sema::ActOnStartNamespaceDef(...)
#20 clang::Parser::ParseNamespace(...)
```

## Reproducer status

A self-contained minimal reproducer has not been achieved. The crash requires a deep module graph (10+ PCM layers through a CRTP injection chain with template class specializations). Simpler module hierarchies do not trigger the crash.

The critical structure is: a module that re-exports multiple partitions, each containing deeply nested template class hierarchies with CRTP base chains, where the final module's namespace `StrongAI` contains many TagDecl entries that are lazily deserialized with DeclUpdateRecords containing template arguments referencing types from the deep chain.

Clang's crash reproducer (preprocessed source + run script) was generated but still requires the project's prebuilt PCMs to reproduce. If helpful for diagnosis, I can provide the complete project tree.

## Environment

- **Clang version**: 23.0.0git (commit 3392ec8cf17ce90fe0859ae31e86cf48f8fa185d)
- **OS**: macOS 15.4 (Darwin 25.3.0), ARM64
- **Target**: arm64-apple-macosx26.0.0

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.