Skip to content

Commit b7fa445

Browse files
committed
WholeProgramDevirt: Fix call target propagation for ptrauth architectures
We can't have a call with a constant target with a ptrauth bundle. Remove the ptrauth bundle operand in such a case rdar://105696396
1 parent 9e0f849 commit b7fa445

File tree

2 files changed

+55
-0
lines changed

2 files changed

+55
-0
lines changed

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ struct DevirtModule {
571571
// optimize a call more than once.
572572
SmallPtrSet<CallBase *, 8> OptimizedCalls;
573573

574+
// Store calls that had their ptrauth bundle removed. They are to be deleted
575+
// at the end of the optimization.
576+
SmallVector<CallBase *, 8> CallsWithPtrAuthBundleRemoved;
577+
574578
// This map keeps track of the number of "unsafe" uses of a loaded function
575579
// pointer. The key is the associated llvm.type.test intrinsic call generated
576580
// by this pass. An unsafe use is one that calls the loaded function pointer
@@ -1204,6 +1208,15 @@ void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
12041208
// !callees metadata.
12051209
CB.setMetadata(LLVMContext::MD_prof, nullptr);
12061210
CB.setMetadata(LLVMContext::MD_callees, nullptr);
1211+
if (CB.getCalledOperand() &&
1212+
CB.getOperandBundle(LLVMContext::OB_ptrauth)) {
1213+
auto *NewCS = CallBase::removeOperandBundle(&CB,
1214+
LLVMContext::OB_ptrauth,
1215+
&CB);
1216+
CB.replaceAllUsesWith(NewCS);
1217+
// Schedule for deletion at the end of pass run.
1218+
CallsWithPtrAuthBundleRemoved.push_back(&CB);
1219+
}
12071220
}
12081221

12091222
// This use is no longer unsafe.
@@ -2369,6 +2382,9 @@ bool DevirtModule::run() {
23692382
for (GlobalVariable &GV : M.globals())
23702383
GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
23712384

2385+
for (auto *CI : CallsWithPtrAuthBundleRemoved)
2386+
CI->eraseFromParent();
2387+
23722388
return true;
23732389
}
23742390

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; RUN: opt -S -passes=wholeprogramdevirt,verify -whole-program-visibility -pass-remarks=wholeprogramdevirt %s 2>&1 | FileCheck %s
2+
3+
target datalayout = "e-p:64:64"
4+
target triple = "x86_64-unknown-linux-gnu"
5+
6+
; CHECK: remark: <unknown>:0:0: single-impl: devirtualized a call to vf
7+
; CHECK: remark: <unknown>:0:0: devirtualized vf
8+
; CHECK-NOT: devirtualized
9+
10+
@vt1 = constant [1 x ptr] [ptr @vf], !type !0
11+
@vt2 = constant [1 x ptr] [ptr @vf], !type !0
12+
13+
define void @vf(ptr %this) {
14+
ret void
15+
}
16+
17+
; CHECK: define void @call
18+
define void @call(ptr %obj) {
19+
%vtable = load ptr, ptr %obj
20+
%pair = call {ptr, i1} @llvm.type.checked.load(ptr %vtable, i32 0, metadata !"typeid")
21+
%fptr = extractvalue {ptr, i1} %pair, 0
22+
%p = extractvalue {ptr, i1} %pair, 1
23+
; CHECK: br i1 true,
24+
br i1 %p, label %cont, label %trap
25+
26+
cont:
27+
; CHECK: call void @vf(
28+
call void %fptr(ptr %obj) [ "ptrauth"(i32 5, i64 120) ]
29+
ret void
30+
31+
trap:
32+
call void @llvm.trap()
33+
unreachable
34+
}
35+
36+
declare {ptr, i1} @llvm.type.checked.load(ptr, i32, metadata)
37+
declare void @llvm.trap()
38+
39+
!0 = !{i32 0, !"typeid"}

0 commit comments

Comments
 (0)