LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 41279 - Crash with SEH and -fprofile-generate
Summary: Crash with SEH and -fprofile-generate
Status: RESOLVED FIXED
Alias: None
Product: new-bugs
Classification: Unclassified
Component: new bugs (show other bugs)
Version: unspecified
Hardware: PC Windows NT
: P enhancement
Assignee: Rong Xu
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-03-28 11:24 PDT by dmajor
Modified: 2019-07-02 13:27 PDT (History)
11 users (show)

See Also:
Fixed By Commit(s): r362995


Attachments
Test case for IR-level instrumentation failure. (69.12 KB, text/plain)
2019-05-24 06:03 PDT, Michael Woerister
Details
catchswitch example (3.04 KB, text/plain)
2019-05-30 11:35 PDT, Reid Kleckner
Details

Note You need to log in before you can comment on or make changes to this bug.
Description dmajor 2019-03-28 11:24:54 PDT
Reproducer:

void f() {
  __try { f(); }
  __except (1) { return; }
  __try { f(); }
  __except (1) { }
}

clang-cl.exe -O2 -clang:-fprofile-generate -c test.cpp

Here's the stack though I'm not sure how much it helps, given the inlining in my release build:

00 clang!`anonymous namespace'::PruneEH::runOnSCC
01 clang!`anonymous namespace'::CGPassManager::runOnModule
02 clang!llvm::legacy::PassManagerImpl::run
03 clang!clang::EmitBackendOutput
04 clang!clang::BackendConsumer::HandleTranslationUnit
05 clang!clang::ParseAST

I wonder if this is the PGO-analogue to the SEH gcov crash in bug 34833.
Comment 1 Michael Woerister 2019-05-24 06:03:52 PDT
Created attachment 22012 [details]
Test case for IR-level instrumentation failure.
Comment 2 Michael Woerister 2019-05-24 06:04:09 PDT
For reference, the Rust compiler is running into the same (or at least similar) problem when compiling with IR-level instrumentation. Compiling the following for `x86_64-pc-windows-msvc` as well as `i686-pc-windows-msvc`

```
fn main() {
    panic!()
}
```

runs into the following LLVM assertion in PGOInstrumentation.cpp:

https://github.com/llvm/llvm-project/blob/release/8.x/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp#L714

The resulting LLVM IR is rather verbose unfortunately, and I was not able to reduce it with `bugpoint`. I'm attaching it anyway.

The Rust compiler's LLVM version is 8.0.
Comment 3 Michael Woerister 2019-05-24 06:06:31 PDT
Another data point that might be interesting. Compiling David Major's test case with a Clang/LLVM (8.0) with assertions enabled runs into the following assertions, both for `i686-pc-windows-gnu` and `x86_64-pc-windows-gnu`:

https://github.com/llvm/llvm-project/blob/release/8.x/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp#L714
Comment 4 dmajor 2019-05-24 07:00:02 PDT
> runs into the following LLVM assertion in PGOInstrumentation.cpp:
> 
> https://github.com/llvm/llvm-project/blob/release/8.x/llvm/lib/Transforms/
> Instrumentation/PGOInstrumentation.cpp#L714

Adding some people who may be interested in this assertion.
Comment 5 Xinliang David Li 2019-05-24 09:05:06 PDT
Rong, can you take a look why the critical edge split fails?
Comment 6 Rong Xu 2019-05-24 09:50:22 PDT
We call llvm::SplitCriticalEdge() to split a critical edge so we can instrument the edge on BB. llvm::SplitCriticalEdge() does not currently handle the edge to an EHPad block. 

This is a known issue and that why I put an assert there.

The complete fix is to do a customized critical edges splitting. But I'm not sure the cost is justified. 

An alternative fix  is to not instrument this critical edge if it cannot be split. I will send a patch following this idea for review.
Comment 7 Rong Xu 2019-05-24 17:15:13 PDT
sent https://reviews.llvm.org/D62439 for review.
Comment 8 Reid Kleckner 2019-05-29 16:03:28 PDT
I see that the linked review landed, but I re-tried the example from the initial report, and the assert on 1509 still fires:

void f() {
  __try { f(); }
  __except (1) { return; }
  __try { f(); }
  __except (1) { }
}

This assert is failing:

  for (auto *InstrBB : InstrumentBBs) {
    IRBuilder<> Builder(InstrBB, InstrBB->getFirstInsertionPt());
    assert(Builder.GetInsertPoint() != InstrBB->end() &&
           "Cannot get the Instrumentation point");
    Builder.CreateCall(
        Intrinsic::getDeclaration(M, Intrinsic::instrprof_increment),
        {ConstantExpr::getBitCast(FuncInfo.FuncNameVar, I8PtrTy),
         Builder.getInt64(FuncInfo.FunctionHash), Builder.getInt32(NumCounters),
         Builder.getInt32(I++)});
  }

The assert will fail for catchswitch blocks where the getFirstInsertionPt returns the end iterator.
Comment 9 Reid Kleckner 2019-05-29 16:03:28 PDT
I see that the linked review landed, but I re-tried the example from the initial report, and the assert on 1509 still fires:

void f() {
  __try { f(); }
  __except (1) { return; }
  __try { f(); }
  __except (1) { }
}

This assert is failing:

  for (auto *InstrBB : InstrumentBBs) {
    IRBuilder<> Builder(InstrBB, InstrBB->getFirstInsertionPt());
    assert(Builder.GetInsertPoint() != InstrBB->end() &&
           "Cannot get the Instrumentation point");
    Builder.CreateCall(
        Intrinsic::getDeclaration(M, Intrinsic::instrprof_increment),
        {ConstantExpr::getBitCast(FuncInfo.FuncNameVar, I8PtrTy),
         Builder.getInt64(FuncInfo.FunctionHash), Builder.getInt32(NumCounters),
         Builder.getInt32(I++)});
  }

The assert will fail for catchswitch blocks where the getFirstInsertionPt returns the end iterator.
Comment 10 Reid Kleckner 2019-05-29 16:04:20 PDT
Sorry for the double comment, I think I hit "enter enter" because I wanted to add... Thanks for looking into this, the fix appears to be quite involved, and it would've been hard for a non-PGO expert to come up with as good of a fix.
Comment 11 Rong Xu 2019-05-29 16:14:43 PDT
(In reply to Reid Kleckner from comment #10)
> Sorry for the double comment, I think I hit "enter enter" because I wanted
> to add... Thanks for looking into this, the fix appears to be quite
> involved, and it would've been hard for a non-PGO expert to come up with as
> good of a fix.

Thanks for verifying this.  Could you give me the IR file?

I did try the reproducer in the comment #1. But I did not have a windows environment and could not reproduce the error in linux.

I was thinking the assertion is the same as in comment #2.
But now, it seems to be different issue.
Comment 12 Reid Kleckner 2019-05-30 11:35:47 PDT
Created attachment 22051 [details]
catchswitch example

Here's the IR. When I compile this with `clang -c t.ll -fprofile-generate`, it reproduces the assertion in PGO instrumentation relating to insertion points.
Comment 13 Rong Xu 2019-05-30 12:39:40 PDT
Thanks Reid for the IR reproducer.

The reason for the failure in the original report is that we want to instrument the fellowing BB:

catch.dispatch4:                                  ; preds = %__try.cont
  %3 = catchswitch within none [label %__except5] unwind to caller

catchswitch needs to be the first instruction for a BB. So the instrumentation pt returned is the end of BB.

I don't think we can instrument this BB.

The fix is probably to filter this kind of BBs.

I will sent a patch for review shortly.
Comment 14 Rong Xu 2019-05-30 13:57:25 PDT
https://reviews.llvm.org/D62700
is out for review.
Comment 15 Reid Kleckner 2019-07-02 13:27:34 PDT
According to Russel, r362995 fixed this issue.