Skip to content

Commit 21af99a

Browse files
authored
[WinEH] Emit state stores for SEH scopes (#116546)
At the moment Windows 32 bit SEH state stores are only emitted for throwing calls. Windows 32 bit SEH state stores should also be emitted before SEH scope begin and before SEH scope end. An invalid inline memory access would otherwise not trigger unwinding, in combination with /EHa. This fixes #90946
1 parent 8df6321 commit 21af99a

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

llvm/lib/Target/X86/X86WinEHState.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,11 +517,28 @@ int WinEHStatePass::getBaseStateForBB(
517517
return BaseState;
518518
}
519519

520+
static bool isIntrinsic(const CallBase &Call, Intrinsic::ID ID) {
521+
const Function *CF = Call.getCalledFunction();
522+
return CF && CF->isIntrinsic() && CF->getIntrinsicID() == ID;
523+
}
524+
525+
static bool isSehScopeEnd(const CallBase &Call) {
526+
return isIntrinsic(Call, Intrinsic::seh_scope_end);
527+
}
528+
529+
static bool isSehScopeBegin(const CallBase &Call) {
530+
return isIntrinsic(Call, Intrinsic::seh_scope_begin);
531+
}
532+
520533
// Calculate the state a call-site is in.
521534
int WinEHStatePass::getStateForCall(
522535
DenseMap<BasicBlock *, ColorVector> &BlockColors, WinEHFuncInfo &FuncInfo,
523536
CallBase &Call) {
524537
if (auto *II = dyn_cast<InvokeInst>(&Call)) {
538+
if (isSehScopeEnd(*II)) {
539+
return getBaseStateForBB(BlockColors, FuncInfo, II->getNormalDest());
540+
}
541+
525542
// Look up the state number of the EH pad this unwinds to.
526543
assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!");
527544
return FuncInfo.InvokeStateMap[II];
@@ -610,6 +627,10 @@ static int getSuccState(DenseMap<BasicBlock *, int> &InitialStates, Function &F,
610627

611628
bool WinEHStatePass::isStateStoreNeeded(EHPersonality Personality,
612629
CallBase &Call) {
630+
if (isSehScopeBegin(Call) || isSehScopeEnd(Call)) {
631+
return true;
632+
}
633+
613634
// If the function touches memory, it needs a state store.
614635
if (isAsynchronousEHPersonality(Personality))
615636
return !Call.doesNotAccessMemory();
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
; RUN: opt -mtriple=i386-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s
2+
3+
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
4+
target triple = "i386-pc-windows-msvc19.42.34433"
5+
6+
%struct.Destructor = type { ptr }
7+
8+
define dso_local void @"?HandleDestructorCallWithException@@YAXPA_N@Z"(ptr noundef %destructorCalled) personality ptr @__CxxFrameHandler3 {
9+
entry:
10+
%destructorCalled.addr = alloca ptr, align 4
11+
%x = alloca %struct.Destructor, align 4
12+
store ptr %destructorCalled, ptr %destructorCalled.addr, align 4
13+
%0 = load ptr, ptr %destructorCalled.addr, align 4
14+
%call = call x86_thiscallcc noundef ptr @"??0Destructor@@QAE@PA_N@Z"(ptr noundef nonnull align 4 dereferenceable(4) %x, ptr noundef %0)
15+
; CHECK: store i32 0, ptr %9, align 4
16+
; CHECK-NEXT: invoke void @llvm.seh.scope.begin()
17+
invoke void @llvm.seh.scope.begin()
18+
to label %invoke.cont unwind label %ehcleanup
19+
20+
invoke.cont:
21+
store i32 1, ptr inttoptr (i32 1 to ptr), align 4
22+
; CHECK: store i32 -1, ptr %10, align 4
23+
; CHECK-NEXT: invoke void @llvm.seh.scope.end()
24+
invoke void @llvm.seh.scope.end()
25+
to label %invoke.cont1 unwind label %ehcleanup
26+
27+
invoke.cont1:
28+
call x86_thiscallcc void @"??1Destructor@@QAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %x) #1
29+
ret void
30+
31+
ehcleanup:
32+
%1 = cleanuppad within none []
33+
call x86_thiscallcc void @"??1Destructor@@QAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %x) #1 [ "funclet"(token %1) ]
34+
cleanupret from %1 unwind to caller
35+
}
36+
37+
declare dso_local i32 @__CxxFrameHandler3(...)
38+
declare dso_local void @llvm.seh.scope.begin() #0
39+
declare dso_local void @llvm.seh.scope.end() #0
40+
41+
declare dso_local x86_thiscallcc noundef ptr @"??0Destructor@@QAE@PA_N@Z"(ptr noundef nonnull returned align 4 dereferenceable(4) %this, ptr noundef %destructorCalled)
42+
declare dso_local x86_thiscallcc void @"??1Destructor@@QAE@XZ"(ptr noundef nonnull align 4 dereferenceable(4) %this) #1
43+
44+
attributes #0 = { nounwind memory(none) }
45+
attributes #1 = { nounwind }

0 commit comments

Comments
 (0)