Skip to content

Commit ac40483

Browse files
committed
Fix a use-after-free in the coro.alloca treatment.
llvm-svn: 368792
1 parent 62a5dde commit ac40483

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

llvm/lib/Transforms/Coroutines/CoroFrame.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,8 @@ static bool localAllocaNeedsStackSave(CoroAllocaAllocInst *AI) {
10421042

10431043
/// Turn each of the given local allocas into a normal (dynamic) alloca
10441044
/// instruction.
1045-
static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas) {
1045+
static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas,
1046+
SmallVectorImpl<Instruction*> &DeadInsts) {
10461047
for (auto AI : LocalAllocas) {
10471048
auto M = AI->getModule();
10481049
IRBuilder<> Builder(AI);
@@ -1075,10 +1076,10 @@ static void lowerLocalAllocas(ArrayRef<CoroAllocaAllocInst*> LocalAllocas) {
10751076
StackSave);
10761077
}
10771078
}
1078-
cast<Instruction>(U)->eraseFromParent();
1079+
DeadInsts.push_back(cast<Instruction>(U));
10791080
}
10801081

1081-
AI->eraseFromParent();
1082+
DeadInsts.push_back(AI);
10821083
}
10831084
}
10841085

@@ -1201,6 +1202,11 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
12011202
continue;
12021203
}
12031204

1205+
// Ignore alloca.get; we process this as part of coro.alloca.alloc.
1206+
if (isa<CoroAllocaGetInst>(I)) {
1207+
continue;
1208+
}
1209+
12041210
for (User *U : I.users())
12051211
if (Checker.isDefinitionAcrossSuspend(I, U)) {
12061212
// We cannot spill a token.
@@ -1214,7 +1220,7 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) {
12141220
moveSpillUsesAfterCoroBegin(F, Spills, Shape.CoroBegin);
12151221
Shape.FrameTy = buildFrameType(F, Shape, Spills);
12161222
Shape.FramePtr = insertSpills(Spills, Shape);
1217-
lowerLocalAllocas(LocalAllocas);
1223+
lowerLocalAllocas(LocalAllocas, DeadInstructions);
12181224

12191225
for (auto I : DeadInstructions)
12201226
I->eraseFromParent();

llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,34 @@ loop2:
202202
; CHECK-NEXT: br i1 %cmp, label %loop2,
203203
; CHECK-NEXT: }
204204

205+
declare {i8*, i32} @prototype_j(i8*)
206+
define {i8*, i32} @j(i8* %buffer, i32 %n) {
207+
entry:
208+
%id = call token @llvm.coro.id.retcon(i32 1024, i32 8, i8* %buffer, i8* bitcast ({i8*, i32} (i8*)* @prototype_j to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*))
209+
%hdl = call i8* @llvm.coro.begin(token %id, i8* null)
210+
br label %forward
211+
212+
back:
213+
; We should encounter this 'get' before we encounter the 'alloc'.
214+
%ptr = call i8* @llvm.coro.alloca.get(token %alloca)
215+
call void @use(i8* %ptr)
216+
call void @llvm.coro.alloca.free(token %alloca)
217+
%k = add i32 %n.val, 1
218+
%cmp = icmp ugt i32 %k, 128
219+
br i1 %cmp, label %forward, label %end
220+
221+
forward:
222+
%n.val = phi i32 [ %n, %entry ], [ %k, %back ]
223+
call void (...) @llvm.coro.suspend.retcon.isVoid(i32 %n.val)
224+
%alloca = call token @llvm.coro.alloca.alloc.i32(i32 %n.val, i32 8)
225+
%inc = add i32 %n.val, 1
226+
br label %back
227+
228+
end:
229+
call i1 @llvm.coro.end(i8* %hdl, i1 0)
230+
unreachable
231+
}
232+
205233
declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*)
206234
declare i8* @llvm.coro.begin(token, i8*)
207235
declare i1 @llvm.coro.suspend.retcon.i1(...)

0 commit comments

Comments
 (0)