Skip to content

Commit 84abcbe

Browse files
committed
Merge pull request #2264 from eeckstein/stack-promotion
Don't stack promote allocations in no-return blocks.
2 parents fc79294 + 7348e48 commit 84abcbe

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

lib/SILOptimizer/Transforms/StackPromotion.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,35 @@ static bool isPromotableAllocInst(SILInstruction *I) {
220220
}
221221

222222
StackPromoter::ChangeState StackPromoter::promote() {
223+
224+
llvm::SetVector<SILBasicBlock *> ReachableBlocks;
225+
226+
// First step: find blocks which end up in a no-return block (terminated by
227+
// an unreachable instruction).
228+
// Search for function-exiting blocks, i.e. return and throw.
229+
for (SILBasicBlock &BB : *F) {
230+
TermInst *TI = BB.getTerminator();
231+
if (TI->isFunctionExiting())
232+
ReachableBlocks.insert(&BB);
233+
}
234+
// Propagate the reachability up the control flow graph.
235+
unsigned Idx = 0;
236+
while (Idx < ReachableBlocks.size()) {
237+
SILBasicBlock *BB = ReachableBlocks[Idx++];
238+
for (SILBasicBlock *Pred : BB->getPreds())
239+
ReachableBlocks.insert(Pred);
240+
}
241+
223242
// Search the whole function for stack promotable allocations.
224243
for (SILBasicBlock &BB : *F) {
244+
245+
// Don't stack promote any allocation inside a code region which ends up in
246+
// a no-return block. Such allocations may missing their final release.
247+
// We would insert the deallocation too early, which may result in a
248+
// use-after-free problem.
249+
if (ReachableBlocks.count(&BB) == 0)
250+
continue;
251+
225252
for (auto Iter = BB.begin(); Iter != BB.end();) {
226253
// The allocation instruction may be moved, so increment Iter prior to
227254
// doing the optimization.

test/SILOptimizer/stack_promotion.sil

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ bb0(%0 : $YY):
3939
return %t : $()
4040
}
4141

42+
sil @consume_int : $@convention(thin) (Int32) -> ()
4243

4344
// CHECK-LABEL: sil @simple_promote
4445
// CHECK: [[O:%[0-9]+]] = alloc_ref [stack] $XX
@@ -68,6 +69,29 @@ bb0:
6869
return %n1 : $XX
6970
}
7071

72+
// CHECK-LABEL: sil @dont_promote_in_unreachable
73+
// CHECK: bb1:
74+
// CHECK-NEXT: alloc_ref $XX
75+
sil @dont_promote_in_unreachable : $@convention(thin) () -> () {
76+
bb0:
77+
cond_br undef, bb1, bb2
78+
79+
bb1:
80+
%o1 = alloc_ref $XX
81+
%f1 = function_ref @xx_init : $@convention(thin) (@guaranteed XX) -> XX
82+
%n1 = apply %f1(%o1) : $@convention(thin) (@guaranteed XX) -> XX
83+
%l1 = ref_element_addr %n1 : $XX, #XX.x
84+
%l2 = load %l1 : $*Int32
85+
%f2 = function_ref @consume_int : $@convention(thin) (Int32) -> ()
86+
%a = apply %f2(%l2) : $@convention(thin) (Int32) -> ()
87+
// An unreachable block may missing the final release.
88+
unreachable
89+
90+
bb2:
91+
%r = tuple ()
92+
return %r : $()
93+
}
94+
7195
// CHECK-LABEL: sil @promote_nested
7296
// CHECK: [[X:%[0-9]+]] = alloc_ref [stack] $XX
7397
// CHECK: [[Y:%[0-9]+]] = alloc_ref [stack] $YY

0 commit comments

Comments
 (0)