Issue 175972
Summary Incorrect coverage counts for code after exception throw sites
Labels new issue
Assignees
Reporter chrisgibson01
    # Description

## Summary

LLVM's source-based code coverage incorrectly reports execution counts for code that never executes when it appears after an exception throw site in the same scope (but outside the throwing function).

## Environment

- **Clang Version**: Ubuntu clang version 21.1.0 (++20250729101116+317403d705ac-1~exp1~20250729101218.12)
- **Target**: x86_64-pc-linux-gnu
- **Platform**: Linux 6.8.0-87-generic x86_64 Ubuntu
- **Build Flags**: `-fprofile-instr-generate -fcoverage-mapping`

## Description

When an exception is thrown inside a try block, coverage instrumentation incorrectly reports that subsequent code in the same scope (after the function call that throws) has executed, even though the exception immediately transfers control to the catch block.

The coverage **correctly** shows 0 executions for code *inside* the throwing function after the throw statement, but **incorrectly** shows non-zero counts for code at the *call site* after the throwing function call.

## Minimal Reproducer

```cpp
// coverage_bug_repro.cpp
#include <iostream>

int i{};

void always_throws()
{
    throw 42;
    ++i;        // Doesn't execute, coverage correctly shows 0 }

int main()
{
    try {
 always_throws();
        ++i;    // Doesn't execute, but coverage shows 1!
    }
    catch(...)
    {
    }

    std::cout << i << '\n'; // outputs: 0
}
```## Steps to Reproduce

```bash
# Compile with coverage instrumentation
clang++ -fprofile-instr-generate -fcoverage-mapping coverage_bug_repro.cpp
 # Run the program and capture profile
LLVM_PROFILE_FILE="repro.profraw" ./a.out

# Merge profile data
llvm-profdata merge -sparse repro.profraw -o repro.profdata
# Generate coverage report
llvm-cov show -instr-profile="" ./a.out
```

## Expected Behavior

Line 17 (`++i;` after the `always_throws()` call) should show **0 executions** because:
- The exception is thrown on line 8
- Control immediately transfers to the catch block
- The code on line 17 never executes
- The program outputs `0`, proving `i` was never incremented

## Actual Behavior

**Coverage report shows:**

```
   15|      1|    try
   16|      1|    { 17|      1|        always_throws();
   18|      1|        ++i;    // BUG: Shows execution count of 1
   19|      1|    }
```
 Line 18 shows execution count of **1**, even though it never executed.

**For comparison**, line 9 (inside `always_throws()` after the throw) correctly shows **0**:

```
    7|      1|{
    8|      1| throw 42;
    9|      0|    ++i;        // Correctly shows 0
   10| 0|}
```

**Proof**: The program outputs `0`, definitively proving that `++i` on line 18 never executed.

_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to