llvm / llvm/llvm-project

[BasicBlockSections] Debug-only instruction suppresses a landing-pad NOP and changes exception behavior

Open
#219,671 1 comment 0 reactions 0 assignees View on GitHub
llvm:codegen
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Summary

Two verifier-valid LLVM IR modules differ by exactly one `#dbg_value` record.
With the same basic-block cluster profile, the version without the record
inserts the NOP required before a zero-offset landing pad and catches a thrown
`bool`. The version with the record omits the NOP and terminates with an
uncaught exception.

This reproduces with an assertions-enabled LLVM 24.0.0git build at revision
`2e3d50b4111f324fb615c3c18d02189caa1ef62d` on x86-64 Linux.

## Reproducer

The following five files are attached. The IR files have a final `.txt`
suffix only because GitHub does not accept `.ll` uploads:

[cluster.txt](https://github.com/user-attachments/files/31595026/cluster.txt)
[reproduce.sh](https://github.com/user-attachments/files/31595025/reproduce.sh)
[runtime-driver.cpp](https://github.com/user-attachments/files/31595029/runtime-driver.cpp)
[with-dbg-value.ll.txt](https://github.com/user-attachments/files/31595028/with-dbg-value.ll.txt)
[without-dbg-value.ll.txt](https://github.com/user-attachments/files/31595027/without-dbg-value.ll.txt)

The cluster file is a valid version-1 Basic Block Sections profile. Both IR
variants use exactly the same profile, and all referenced basic-block IDs are
present in the generated MachineFunction.

Run:

```sh
bash reproduce.sh
```

The script verifies both IR modules with `llvm-as` and
`opt -passes=verify`, enables `-verify-machineinstrs`, compiles both
modules, and runs them.

## Actual behavior

```text
without #dbg_value: NOOP=1 status=0
with #dbg_value: NOOP=0 status=134
terminate called after throwing an instance of 'bool'
```

Immediately before `bbsections-prepare`, the ordinary Machine IR is identical
between the two cases. The additional `#dbg_value` lowers to a `DBG_VALUE` in
a block with no ordinary machine instructions. After the pass, the ordinary
Machine IR differs by the single landing-pad `NOOP` shown above. The runtime
result was stable across 20 runs of each executable.

## Cause

`avoidZeroOffsetLandingPad()` in
`llvm/lib/CodeGen/BasicBlockSections.cpp` uses raw block emptiness when finding
the first non-empty block in each section:

```cpp
MBB.empty() || MBB.getSectionID() == CurrentSection
```

The `DBG_VALUE` makes `MBB.empty()` false even though the block has no ordinary
instructions. This updates `CurrentSection` before the landing pad is visited,
so the landing pad is no longer treated as the first non-empty block in its
section and the NOP is omitted.

## Expected behavior

Debug-only instructions should not affect this decision. Both modules should
insert the landing-pad NOP and catch the exception successfully.

## Scope

The reproducer was reduced from LLVM's upstream
`llvm/test/CodeGen/X86/basic-block-sections-eh.ll` test. A natural C/C++
frontend input producing this exact debug-only block shape is not currently
known.

Contributor guide

Open the contributing guide

Research direction

Start by running bash reproduce.sh and reading llvm/lib/CodeGen/BasicBlockSections.cpp, especially avoidZeroOffsetLandingPad(). Compare the attached IR variants and the upstream llvm/test/CodeGen/X86/basic-block-sections-eh.ll test. Done means debug-only instructions no longer change the landing-pad decision, both variants insert the NOP, and the exception is caught successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.