Skip to content

Commit e3ade39

Browse files
authored
Merge pull request swiftlang#35605 from meg-gupta/ossabugs1
2 parents 43293ea + 78a6213 commit e3ade39

File tree

4 files changed

+95
-18
lines changed

4 files changed

+95
-18
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,13 +472,14 @@ struct BorrowedValue {
472472
/// reborrows, place them in BorrowingOperand form into \p
473473
/// foundReborrows. Returns true if we appended any such reborrows to
474474
/// foundReborrows... false otherwise.
475-
bool
476-
gatherReborrows(SmallVectorImpl<BorrowingOperand> &foundReborrows) const {
475+
bool gatherReborrows(SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>>
476+
&foundReborrows) const {
477477
bool foundAnyReborrows = false;
478478
for (auto *op : value->getUses()) {
479479
if (auto borrowingOperand = BorrowingOperand::get(op)) {
480480
if (borrowingOperand.isReborrow()) {
481-
foundReborrows.push_back(*borrowingOperand);
481+
foundReborrows.push_back(
482+
{value->getParentBlock(), op->getOperandNumber()});
482483
foundAnyReborrows = true;
483484
}
484485
}

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ struct OwnershipFixupContext {
3939
JointPostDominanceSetComputer &jointPostDomSetComputer;
4040

4141
SmallVector<Operand *, 8> transitiveBorrowedUses;
42-
SmallVector<BorrowingOperand, 8> recursiveReborrows;
42+
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> recursiveReborrows;
4343

4444
/// Extra state initialized by OwnershipRAUWFixupHelper::get() that we use
4545
/// when RAUWing addresses. This ensures we do not need to recompute this

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ insertOwnedBaseValueAlongBranchEdge(BranchInst *bi, SILValue innerCopy,
100100
}
101101

102102
static bool findTransitiveBorrowedUses(
103-
SILValue value, SmallVectorImpl<Operand *> &usePoints,
104-
SmallVectorImpl<BorrowingOperand> &reborrowPoints) {
103+
SILValue value, SmallVectorImpl<Operand *> &usePoints,
104+
SmallVectorImpl<std::pair<SILBasicBlock *, unsigned>> &reborrowPoints) {
105105
assert(value.getOwnershipKind() == OwnershipKind::Guaranteed);
106106

107107
unsigned firstOffset = usePoints.size();
@@ -165,7 +165,9 @@ static bool findTransitiveBorrowedUses(
165165
[&](Operand *scopeEndingUse) {
166166
if (auto scopeEndingBorrowingOp = BorrowingOperand(scopeEndingUse)) {
167167
if (scopeEndingBorrowingOp.isReborrow()) {
168-
reborrowPoints.push_back(scopeEndingUse);
168+
auto *branch = scopeEndingUse->getUser();
169+
reborrowPoints.push_back(
170+
{branch->getParent(), scopeEndingUse->getOperandNumber()});
169171
return true;
170172
}
171173
}
@@ -239,8 +241,11 @@ static bool canFixUpOwnershipForRAUW(SILValue oldValue, SILValue newValue,
239241
if (oldValue.getOwnershipKind() == OwnershipKind::Guaranteed) {
240242
// Check that the old lifetime can be extended and record the necessary
241243
// book-keeping in the OwnershipFixupContext.
242-
return findTransitiveBorrowedUses(oldValue, context.transitiveBorrowedUses,
243-
context.recursiveReborrows);
244+
if (!findTransitiveBorrowedUses(oldValue, context.transitiveBorrowedUses,
245+
context.recursiveReborrows)) {
246+
context.clear();
247+
return false;
248+
}
244249
}
245250
return true;
246251
}
@@ -430,18 +435,20 @@ OwnershipLifetimeExtender::createPlusZeroBorrow(SILValue newValue,
430435
//===----------------------------------------------------------------------===//
431436

432437
static void eliminateReborrowsOfRecursiveBorrows(
433-
ArrayRef<BorrowingOperand> transitiveReborrows,
438+
ArrayRef<std::pair<SILBasicBlock *, unsigned>> transitiveReborrows,
434439
SmallVectorImpl<Operand *> &usePoints, InstModCallbacks &callbacks) {
435440
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8>
436441
baseBorrowedValuePair;
437442
// Ok, we have transitive reborrows.
438-
for (auto borrowingOperand : transitiveReborrows) {
443+
for (auto it : transitiveReborrows) {
439444
// We eliminate the reborrow by creating a new copy+borrow at the reborrow
440445
// edge from the base value and using that for the reborrow instead of the
441446
// actual value. We of course insert an end_borrow for our original incoming
442447
// value.
448+
auto *bi = cast<BranchInst>(it.first->getTerminator());
449+
auto &op = bi->getOperandRef(it.second);
450+
BorrowingOperand borrowingOperand(&op);
443451
SILValue value = borrowingOperand->get();
444-
auto *bi = cast<BranchInst>(borrowingOperand->getUser());
445452
SILBuilderWithScope reborrowBuilder(bi);
446453
// Use an auto-generated location here, because the branch may have an
447454
// incompatible LocationKind
@@ -501,15 +508,19 @@ static void eliminateReborrowsOfRecursiveBorrows(
501508
}
502509
}
503510

504-
static void rewriteReborrows(SILValue newBorrowedValue,
505-
ArrayRef<BorrowingOperand> foundReborrows,
506-
InstModCallbacks &callbacks) {
511+
static void
512+
rewriteReborrows(SILValue newBorrowedValue,
513+
ArrayRef<std::pair<SILBasicBlock *, unsigned>> foundReborrows,
514+
InstModCallbacks &callbacks) {
507515
// Each initial reborrow that we have is a use of oldValue, so we know
508516
// that copy should be valid at the reborrow.
509517
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8>
510518
baseBorrowedValuePair;
511-
for (auto reborrow : foundReborrows) {
512-
auto *bi = cast<BranchInst>(reborrow.op->getUser());
519+
for (auto it : foundReborrows) {
520+
auto *bi = cast<BranchInst>(it.first->getTerminator());
521+
auto &op = bi->getOperandRef(it.second);
522+
BorrowingOperand reborrow(&op);
523+
513524
SILBuilderWithScope reborrowBuilder(bi);
514525
// Use an auto-generated location here, because the branch may have an
515526
// incompatible LocationKind
@@ -713,7 +724,7 @@ SILBasicBlock::iterator OwnershipRAUWUtility::handleGuaranteed() {
713724
// non-dominating copy value, allowing us to force our borrowing value to
714725
// need a base phi argument (the one of our choosing).
715726
if (auto oldValueBorrowedVal = BorrowedValue::get(oldValue)) {
716-
SmallVector<BorrowingOperand, 8> foundReborrows;
727+
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> foundReborrows;
717728
if (oldValueBorrowedVal.gatherReborrows(foundReborrows)) {
718729
rewriteReborrows(newBorrowedValue, foundReborrows, ctx.callbacks);
719730
}

test/SILOptimizer/cse_ossa_nontrivial.sil

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,68 @@ bb8:
596596
return %res : $()
597597
}
598598

599+
struct RecurStruct {
600+
var val:NonTrivialStruct
601+
}
602+
603+
// Test to make sure we do not crash on a use after free when the branch instructions in bb1 and bb2 are deleted
604+
// CHECK-LABEL: sil [ossa] @test_useafterfreeinrauw :
605+
// CHECK: bb0
606+
// CHECK: struct_extract
607+
// CHECK-NOT: struct_extract
608+
// CHECK: cond_br
609+
// CHECK-LABEL: } // end sil function 'test_useafterfreeinrauw'
610+
sil [ossa] @test_useafterfreeinrauw : $@convention(thin) (@guaranteed RecurStruct) -> @owned NonTrivialStruct {
611+
bb0(%0 : @guaranteed $RecurStruct):
612+
%1 = struct_extract %0 : $RecurStruct, #RecurStruct.val
613+
debug_value %1 : $NonTrivialStruct
614+
%2 = struct_extract %0 : $RecurStruct, #RecurStruct.val
615+
cond_br undef, bb1, bb2
616+
617+
bb1:
618+
%3 = struct_extract %2 : $NonTrivialStruct, #NonTrivialStruct.val
619+
%borrow3 = begin_borrow %3 : $Klass
620+
br bb3(%borrow3 : $Klass)
621+
622+
bb2:
623+
%4 = struct_extract %2 : $NonTrivialStruct, #NonTrivialStruct.val
624+
%borrow4 = begin_borrow %4 : $Klass
625+
br bb3(%borrow4 : $Klass)
626+
627+
bb3(%borrow : @guaranteed $Klass):
628+
end_borrow %borrow : $Klass
629+
%copy = copy_value %1 : $NonTrivialStruct
630+
return %copy : $NonTrivialStruct
631+
}
632+
633+
// Test to make sure we clear the context if we fail while checking if ownership rauw is possible
634+
// CHECK-LABEL: sil [ossa] @test_rauwfailsandthensucceeds :
635+
// CHECK: bb0
636+
// CHECK: struct_extract
637+
// CHECK: struct_extract
638+
// CHECK: struct $_SliceBuffer
639+
// CHECK-NOT: struct $_SliceBuffer
640+
// CHECK-LABEL: } // end sil function 'test_rauwfailsandthensucceeds'
641+
sil [ossa] @test_rauwfailsandthensucceeds : $@convention(method) <Element> (UnsafeMutablePointer<Element>, @guaranteed _ContiguousArrayBuffer<Element>, Int, UInt) -> @owned _SliceBuffer<Element> {
642+
bb0(%0 : $UnsafeMutablePointer<Element>, %1 : @guaranteed $_ContiguousArrayBuffer<Element>, %2 : $Int, %3 : $UInt):
643+
%4 = struct_extract %1 : $_ContiguousArrayBuffer<Element>, #_ContiguousArrayBuffer._storage
644+
%5 = copy_value %4 : $__ContiguousArrayStorageBase
645+
%6 = init_existential_ref %5 : $__ContiguousArrayStorageBase : $__ContiguousArrayStorageBase, $AnyObject
646+
%7 = struct_extract %1 : $_ContiguousArrayBuffer<Element>, #_ContiguousArrayBuffer._storage
647+
%8 = ref_tail_addr %7 : $__ContiguousArrayStorageBase, $Element
648+
%9 = address_to_pointer %8 : $*Element to $Builtin.RawPointer
649+
%10 = struct $UnsafeMutablePointer<Element> (%9 : $Builtin.RawPointer)
650+
%11 = begin_borrow %6 : $AnyObject
651+
%12 = struct $_SliceBuffer<Element> (%11 : $AnyObject, %0 : $UnsafeMutablePointer<Element>, %2 : $Int, %3 : $UInt)
652+
%13 = copy_value %12 : $_SliceBuffer<Element>
653+
end_borrow %11 : $AnyObject
654+
destroy_value %13 : $_SliceBuffer<Element>
655+
%14 = begin_borrow %6 : $AnyObject
656+
%15 = struct $_SliceBuffer<Element> (%14 : $AnyObject, %0 : $UnsafeMutablePointer<Element>, %2 : $Int, %3 : $UInt)
657+
%16 = copy_value %15 : $_SliceBuffer<Element>
658+
end_borrow %14 : $AnyObject
659+
%17 = struct $_SliceBuffer<Element> (%6 : $AnyObject, %0 : $UnsafeMutablePointer<Element>, %2 : $Int, %3 : $UInt)
660+
destroy_value %17 : $_SliceBuffer<Element>
661+
return %16 : $_SliceBuffer<Element>
662+
}
663+

0 commit comments

Comments
 (0)