llvm / llvm/llvm-project

[BPF] clang SIGSEGV in CGDebugInfo::EmitFunctionDecl with -g (DILocalVariable::getImpl)

Open
#213,714 2 comments 0 reactions 0 assignees View on GitHub
clang:codegen crash debuginfo
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

### Summary

Clang SIGSEGV (exit code 139) when compiling for the BPF target with `-g` (debug info). The crash occurs in `CGDebugInfo::EmitFunctionDecl` while creating a `DILocalVariable` for an external function declaration's parameter, triggered at the end of the translation unit (`ActOnEndOfTranslationUnit`). Reproduces on clang 19, 21, and 23 trunk — **not fixed** as of clang 23.

This is distinct from #147212, which crashes in the same `EmitFunctionDecl` entry point but in the `CollectRecordFields` → `getASTRecordLayout` subtree (recursive struct layout). The crash here is on the `createParameterVariable` → `DILocalVariable::getImpl` → `MetadataTracking::track` path.

### Reproducer

Preprocessed source (self-contained, no include dependencies; preprocessed with clang 23): https://gist.github.com/choury/b917f18b82e8a2e1d90269be8b68e192

Triggered by compiling a file from OpenSSL 3.0 (`providers/implementations/signature/rsa_sig.c`), but the crash is in clang/LLVM itself, independent of any pass plugin or custom header — `-target bpf -g` alone reproduces it (no `-fpass-plugin=`).

### Compile command

```bash
clang -target bpf -mcpu=v4 -O1 -mllvm -bpf-stack-size=131072 \
-g -Wno-error=int-conversion \
-DL_ENDIAN -U__SIZEOF_INT128__ -DOPENSSL_BUILDING_OPENSSL \
-c rsa_sig.c -o /dev/null
```

Note: `-mllvm -bpf-stack-size=131072` is required to raise the BPF stack limit so the function reaches codegen (without it, a normal "stack limit exceeded" error fires first).

### Stack dump (clang 23 trunk)

```
Stack dump:
0. Program arguments: clang -target bpf -mcpu=v4 -O1 -mllvm -bpf-stack-size=131072 -g ...
1. parser at end of file
#4 llvm::MetadataTracking::track(...) libLLVM-23
#5 llvm::MDNode::MDNode(...) libLLVM-23
#6 llvm::DILocalVariable::getImpl(...) libLLVM-23
#7 llvm::DIBuilder::createParameterVariable(...) libLLVM-23
#8 clang::CodeGen::CGDebugInfo::EmitFunctionDecl(...) libclang-cpp-23
#9 clang::Sema::ActOnEndOfTranslationUnit() libclang-cpp-23
#10 clang::Parser::ParseTopLevelDecl(...)
clang: error: clang frontend command failed with exit code 139
```

### Key observations

1. **`-g` is the trigger.** Without `-g` (or with `-debug-info-kind=none`), the same file compiles (or fails with a normal, unrelated BPF SelectionDAG error). Tested with `-debug-info-kind=limited|standalone|line-tables-only` → all crash; `none` → OK.
2. **`-target bpf` is required.** The same file with `--target=x86_64-linux-gnu -g` compiles cleanly. BPF-specific.
3. **No pass plugin involved.** Reproduces with stock clang, no `-fpass-plugin=`.
4. **Deterministic, not a race.** The same file crashes 100% across repeated runs. It only *appears* sporadic in a parallel build because only a fraction of source files contain the triggering external declaration shape.

### Version matrix

Same reproducer (`rsa_sig.c`, preprocessed with clang 23), all three crash in the **identical** `EmitFunctionDecl → DILocalVariable::getImpl` stack frame:

| clang version | result |
|---|---|
| **19.1.7** (Debian) | **SIGSEGV** (exit 139) |
| **21.1.8** | **SIGSEGV** (exit 139) |
| **23 trunk** `cd3bfc1f9926` (2026-06-22) | **SIGSEGV** (exit 139) |

So the bug is **not fixed** on clang 23 trunk. (One earlier reproducer file from the same tree, `encoder_lib.c`, happened to stop crashing on 21/23 — but that was incidental, its triggering declaration shape apparently shifted; `rsa_sig.c` crashes consistently across all three versions.)

### Workaround

Drop `-g` (and the dependent `-fstack-size-section`) when compiling BPF code that triggers this. The bug is still present on trunk (clang 23) as of 2026-06-22.

Contributor guide

Open the contributing guide

Research direction

Run the supplied clang command against the linked preprocessed reproducer and confirm the SIGSEGV in the EmitFunctionDecl → createParameterVariable → DILocalVariable::getImpl path. Then read the compiler and debug-info code around CGDebugInfo::EmitFunctionDecl and reproduce across the listed debug-info modes and targets. Done means the BPF reproducer no longer crashes with -g while the existing non-crash behavior remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.