[clang] valgrind: uninitialised-value read in FunctionProtoType ctor on x86_64 (regression in clang-21+)
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
## Summary
Compiling a one-line C++ TU under valgrind reports an uninitialised-value read in `clang::FunctionProtoType::FunctionProtoType` starting in clang-21.1.8.
The same TU is clean on clang-20.1.8 and clean on every aarch64 build I've tested. The regression is x86_64-only and entered between `release/20.x` and
`release/21.x`.
## Minimal reproducer
```cpp
int main() { return 0; }
```
```
$ valgrind --track-origins=yes --error-exitcode=1 \
/usr/lib/llvm-22/bin/clang-22 -c -O0 -o /tmp/r.o repro.cc
==N== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
```
## Bisection by major version
apt.llvm.org packages on Ubuntu 24.04 / x86_64, valgrind 3.22.0:
| clang | source | ERROR SUMMARY |
| --- | --- | --- |
| 20.1.8 (`87f0227cb601`) | `int main() { return 0; }` | 0 errors from 0 contexts |
| 21.1.8 (`2078da43e25a`) | same | **1 error from 1 context** |
| 22.1.3 (`4250a0fc5de9`) | same | 1 error from 1 context |
aarch64 (Ubuntu 24.04 arm64): 0 errors on every version. The regression is x86_64-only.
## Trace
```
==N== Conditional jump or move depends on uninitialised value(s)
==N== at clang::FunctionProtoType::FunctionProtoType(QualType, ArrayRef,
QualType,
FunctionProtoType::ExtProtoInfo const&)
==N== by clang::ASTContext::getFunctionTypeInternal(...)
==N== by
==N== by clang::Sema::GetTypeForDeclarator(clang::Declarator&)
==N== by clang::Sema::HandleDeclarator(...)
==N== by clang::Sema::ActOnStartOfFunctionDef(...)
==N== by clang::Parser::ParseFunctionDefinition(...)
==N== by clang::Parser::ParseDeclGroup(...)
==N== ...
==N== by clang::ParseAST(clang::Sema&, bool, bool)
==N== by clang::FrontendAction::Execute()
==N== Uninitialised value was created by a stack allocation
==N== at
```
The uninitialised value comes from a stack frame in libclang-cpp; the apt.llvm.org packages do not ship debug symbols, so I cannot resolve the exact
origin function. The reader is `FunctionProtoType`'s constructor, called via `ASTContext::getFunctionTypeInternal` for the `int main()` declaration's
type.
## Wider blast radius
A slightly richer TU explodes the context count on clang-22 but not on clang-20:
```cpp
template struct B { T x; T y; T z; };
template auto make() { return B{1}; } // partial init → fill empty
int caller() { auto b = make(); return b.x + b.y + b.z; }
```
| clang | ERROR SUMMARY |
| --- | --- |
| 20.1.8 | 0 errors from 0 contexts |
| 21.1.8 | 8 errors from 7 contexts |
| 22.1.3 | 1386 errors from 1000 contexts (cap) |
Among the contexts on clang-22 are `clang::InitListExpr::resizeInits`, `clang::InitListExpr::isTransparent`, and `clang::Sema::CheckForIntOverflow`. The
same family of uninit reads, presumably amplified by additional readers added between 21.x and 22.x.
## Suspected window
`87f0227cb60147` (release/20.x tip) → `2078da43e25a4623` (release/21.x tip). I haven't build-bisected. Suspects ranked by how directly they touch readers
in the trace:
1. `cffe7cb745a` — `[clang] Fix isConstantInitializer handling of transparent init lists.` (#148030).
2. `0d02150c3d7` — `[clang][AST] Reduce some AST node size.` (#142585) — moves bitfields into `Stmt`'s shared bitfield slack; could leave bits uninit if
a constructor doesn't write them.
3. `5cf7d871b03` (#144432), `37ece04e096` (#140102), `d1ba2692ee5` (#144930) — `getTrailingObjects` refactors; could change AST trailing-array layout.
Happy to bisect to a single commit on a faster builder; the reproducer is small enough for `git bisect run`.
## Environment
- Host: macOS arm64 (Docker Desktop 29.4 with linux/amd64 emulation via QEMU).
- Container: `ubuntu:24.04` x86_64.
- valgrind 3.22.0.
- gcc-12 / g++-12 (the clang binaries themselves are apt.llvm.org prebuilds).
Contributor guide
Research direction
Start with the minimal C++ reproducer and run the Valgrind command on x86_64, then use git bisect between 87f0227cb60147 and 2078da43e25a4623. Trace the named FunctionProtoType constructor through ASTContext::getFunctionTypeInternal and inspect the suspected AST and trailing-object changes. Done means identifying and fixing the regression so the reproducer no longer reports uninitialised reads, including the richer TU case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100