| Issue |
181505
|
| Summary |
[clang] Assertion failure "Bitfield access unit is not clipped" with packed struct + zero-width bitfield (MinGW targets)
|
| Labels |
clang
|
| Assignees |
|
| Reporter |
Z3rox-dev
|
## Summary
Clang crashes with an assertion failure in `CGRecordLayoutBuilder.cpp` when compiling
a packed struct that contains a non-bitfield member smaller than `int`, followed by a
bitfield, a zero-width bitfield (`unsigned : 0`), and another bitfield.
The crash happens at **all optimization levels** (-O0, -O1, -O2, -O3, -Os) and is
**specific to MinGW targets** (`*-w64-windows-gnu`). Linux and MSVC targets are not affected.
## Reproducer
```c
#pragma pack(1)
struct S {
char f1;
unsigned f3 : 1;
unsigned : 0;
unsigned f4 : 1;
};
struct S g;
```
**Compile with:** `clang -c -std=c99 reproducer.c`
## Assertion
```
Assertion failed: M.Offset >= Tail && "Bitfield access unit is not clipped",
file clang/lib/CodeGen/CGRecordLayoutBuilder.cpp, line 960
```
Stack trace points to `CGRecordLowering::checkBitfieldClipping()` called from
`CGRecordLowering::lower()` → `CodeGenTypes::ComputeRecordLayout()`.
## Environment
- **Clang version:** 23.0.0git (built from source, trunk)
- **Build config:** Release + assertions
- **GCC 15.2.0:** Compiles the same code without any issue
## Affected targets
| Target | Result |
|--------|--------|
| `x86_64-w64-windows-gnu` (MinGW 64-bit) | **CRASH** |
| `i686-w64-windows-gnu` (MinGW 32-bit) | **CRASH** |
| `x86_64-linux-gnu` | OK |
| `x86_64-pc-windows-msvc` | OK |
## Key ingredients for the crash
All of these are required simultaneously:
1. `#pragma pack(N)` where N < `alignof(int)` — `pack(1)` and `pack(2)` both crash
2. A **non-bitfield member** smaller than `int` (`char` or `short`; `int` does NOT crash)
3. A **zero-width bitfield** (`unsigned : 0`)
4. At least one bitfield **after** the zero-width bitfield
Removing any one of these ingredients prevents the crash.
## Variations tested
| Struct definition | Result |
|---|---|
| `pack(1), char + bf + :0 + bf` | **CRASH** |
| `pack(2), char + bf + :0 + bf` | **CRASH** |
| `pack(1), short + bf + :0 + bf` | **CRASH** |
| `pack(1), int + bf + :0 + bf` | OK |
| No pragma pack, `char + bf + :0 + bf` | OK |
| `pack(1), char + bf + bf` (no `:0`) | OK |
| `pack(1), char + bf + :0` (no field after `:0`) | OK |
## Analysis
The assertion fires in `checkBitfieldClipping()` which verifies that bitfield
access units computed by `accumulateBitfields()` do not overlap. The combination
of `#pragma pack` with a non-bitfield member smaller than the natural alignment
causes the access units to be computed with overlapping offsets, but only under
MinGW's bitfield layout rules (which differ from the Itanium/MSVC ABI).
## Related issue
[#148838](https://github.com/llvm/llvm-project/issues/148838) has the same assertion
but is triggered through LLDB with C++ `[[no_unique_address]]` — a different code path.
## How this was found
Found via [CSmith](https://embed.cs.utah.edu/csmith/) fuzzing (seed 1027636316).
Reduced from a 108KB generated file to the 8-line reproducer above.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs