Skip to content

Commit 2d2a56f

Browse files
authored
Merge pull request #59360 from eeckstein/fix-store-borrow-verification
Fix store borrow verification
2 parents e60fb30 + a98d9af commit 2d2a56f

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

docs/SIL.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3745,6 +3745,8 @@ store_borrow
37453745

37463746
Stores the value ``%0`` to a stack location ``%1``, which must be an
37473747
``alloc_stack $T``.
3748+
The stack location must not be modified by other instructions than
3749+
``store_borrow``.
37483750
The stored value is alive until the ``dealloc_stack`` or until another
37493751
``store_borrow`` overwrites the value. During the its lifetime, the stored
37503752
value must not be modified or destroyed.

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class MemoryLifetimeVerifier {
8989
/// Register the destination address of a store_borrow as borrowed location.
9090
void registerStoreBorrowLocation(SILValue addr);
9191

92+
/// Registers all store_borrow instructions in a block.
93+
void registerStoreBorrowsInBlock(SILBasicBlock *block);
94+
9295
/// Handles locations of the predecessor's terminator, which are only valid
9396
/// in \p block.
9497
/// Example: @out results of try_apply. They are only valid in the
@@ -286,6 +289,13 @@ void MemoryLifetimeVerifier::registerStoreBorrowLocation(SILValue addr) {
286289
}
287290
}
288291

292+
void MemoryLifetimeVerifier::registerStoreBorrowsInBlock(SILBasicBlock *block) {
293+
for (SILInstruction &inst : *block) {
294+
if (auto *sbi = dyn_cast<StoreBorrowInst>(&inst))
295+
registerStoreBorrowLocation(sbi->getDest());
296+
}
297+
}
298+
289299
void MemoryLifetimeVerifier::initDataflow(BitDataflow &dataFlow) {
290300
// Initialize the entry and exit sets to all-bits-set. Except for the function
291301
// entry.
@@ -579,7 +589,6 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
579589
case SILInstructionKind::StoreBorrowInst: {
580590
SILValue destAddr = cast<StoreBorrowInst>(&I)->getDest();
581591
locations.setBits(bits, destAddr);
582-
registerStoreBorrowLocation(destAddr);
583592
break;
584593
}
585594
case SILInstructionKind::CopyAddrInst: {
@@ -764,6 +773,7 @@ void MemoryLifetimeVerifier::verify() {
764773
locations.handleSingleBlockLocations([this](SILBasicBlock *block) {
765774
storeBorrowLocations.clear();
766775
Bits bits(locations.getNumLocations());
776+
registerStoreBorrowsInBlock(block);
767777
checkBlock(block, bits);
768778
});
769779
}

test/SIL/memory_lifetime_failures.sil

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,36 @@ bb0(%0 : @guaranteed $Optional<T>):
361361
return %res : $()
362362
}
363363

364+
// CHECK: SIL memory lifetime failure in @test_store_borrow_single_block: store-borrow location cannot be written
365+
sil [ossa] @test_store_borrow_single_block : $@convention(thin) (@guaranteed T) -> () {
366+
bb0(%0 : @guaranteed $T):
367+
%stk = alloc_stack $T
368+
%copy = copy_value %0 : $T
369+
store %copy to [init] %stk : $*T
370+
%ld = load [take] %stk : $*T
371+
destroy_value %ld : $T
372+
store_borrow %0 to %stk : $*T
373+
dealloc_stack %stk : $*T
374+
%8 = tuple ()
375+
return %8 : $()
376+
}
377+
378+
// CHECK: SIL memory lifetime failure in @test_store_borrow_multi_block: store-borrow location cannot be written
379+
sil [ossa] @test_store_borrow_multi_block : $@convention(thin) (@guaranteed T) -> () {
380+
bb0(%0 : @guaranteed $T):
381+
%stk = alloc_stack $T
382+
%copy = copy_value %0 : $T
383+
store %copy to [init] %stk : $*T
384+
%ld = load [take] %stk : $*T
385+
destroy_value %ld : $T
386+
br bb1
387+
bb1:
388+
store_borrow %0 to %stk : $*T
389+
dealloc_stack %stk : $*T
390+
%8 = tuple ()
391+
return %8 : $()
392+
}
393+
364394
// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should be
365395
sil [ossa] @test_cast_br_take_always : $@convention(thin) <U, V> (@in U) -> () {
366396
bb0(%0 : $*U):

0 commit comments

Comments
 (0)