mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[MemoryLifetimeVerifier] Permit leaks in dead-ends
This commit is contained in:
@@ -1676,7 +1676,8 @@ public:
|
||||
}
|
||||
|
||||
/// Verifies the lifetime of memory locations in the function.
|
||||
void verifyMemoryLifetime(CalleeCache *calleeCache);
|
||||
void verifyMemoryLifetime(CalleeCache *calleeCache,
|
||||
DeadEndBlocks *deadEndBlocks);
|
||||
|
||||
/// Verifies ownership of the function.
|
||||
/// Since we don't have complete lifetimes everywhere, computes DeadEndBlocks
|
||||
|
||||
@@ -12,13 +12,14 @@
|
||||
|
||||
#define DEBUG_TYPE "sil-memory-lifetime-verifier"
|
||||
#include "swift/Basic/Assertions.h"
|
||||
#include "swift/SIL/MemoryLocations.h"
|
||||
#include "swift/SIL/BitDataflow.h"
|
||||
#include "swift/SIL/CalleeCache.h"
|
||||
#include "swift/SIL/SILBasicBlock.h"
|
||||
#include "swift/SIL/SILFunction.h"
|
||||
#include "swift/SIL/ApplySite.h"
|
||||
#include "swift/SIL/BasicBlockDatastructures.h"
|
||||
#include "swift/SIL/BasicBlockUtils.h"
|
||||
#include "swift/SIL/BitDataflow.h"
|
||||
#include "swift/SIL/CalleeCache.h"
|
||||
#include "swift/SIL/MemoryLocations.h"
|
||||
#include "swift/SIL/SILBasicBlock.h"
|
||||
#include "swift/SIL/SILFunction.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
using namespace swift;
|
||||
@@ -43,6 +44,7 @@ class MemoryLifetimeVerifier {
|
||||
|
||||
SILFunction *function;
|
||||
CalleeCache *calleeCache;
|
||||
DeadEndBlocks *deadEndBlocks;
|
||||
MemoryLocations locations;
|
||||
|
||||
/// alloc_stack memory locations which are used for store_borrow.
|
||||
@@ -140,11 +142,12 @@ class MemoryLifetimeVerifier {
|
||||
}
|
||||
|
||||
public:
|
||||
MemoryLifetimeVerifier(SILFunction *function, CalleeCache *calleeCache) :
|
||||
function(function),
|
||||
calleeCache(calleeCache),
|
||||
locations(/*handleNonTrivialProjections*/ true,
|
||||
/*handleTrivialLocations*/ true) {}
|
||||
MemoryLifetimeVerifier(SILFunction *function, CalleeCache *calleeCache,
|
||||
DeadEndBlocks *deadEndBlocks)
|
||||
: function(function), calleeCache(calleeCache),
|
||||
deadEndBlocks(deadEndBlocks),
|
||||
locations(/*handleNonTrivialProjections*/ true,
|
||||
/*handleTrivialLocations*/ true) {}
|
||||
|
||||
/// The main entry point to verify the lifetime of all memory locations in
|
||||
/// the function.
|
||||
@@ -883,7 +886,12 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
|
||||
}
|
||||
case SILInstructionKind::DeallocStackInst: {
|
||||
SILValue opVal = cast<DeallocStackInst>(&I)->getOperand();
|
||||
requireBitsClear(bits & nonTrivialLocations, opVal, &I);
|
||||
if (!deadEndBlocks->isDeadEnd(I.getParent())) {
|
||||
// TODO: rdar://159311784: Maybe at some point the invariant will be
|
||||
// enforced that values stored into addresses
|
||||
// don't leak in dead-ends.
|
||||
requireBitsClear(bits & nonTrivialLocations, opVal, &I);
|
||||
}
|
||||
// Needed to clear any bits of trivial locations (which are not required
|
||||
// to be zero).
|
||||
locations.clearBits(bits, opVal);
|
||||
@@ -973,7 +981,8 @@ void MemoryLifetimeVerifier::verify() {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void SILFunction::verifyMemoryLifetime(CalleeCache *calleeCache) {
|
||||
MemoryLifetimeVerifier verifier(this, calleeCache);
|
||||
void SILFunction::verifyMemoryLifetime(CalleeCache *calleeCache,
|
||||
DeadEndBlocks *deadEndBlocks) {
|
||||
MemoryLifetimeVerifier verifier(this, calleeCache, deadEndBlocks);
|
||||
verifier.verify();
|
||||
}
|
||||
|
||||
@@ -7380,7 +7380,7 @@ public:
|
||||
|
||||
if (F->hasOwnership() && F->shouldVerifyOwnership() &&
|
||||
!mod.getASTContext().hadError()) {
|
||||
F->verifyMemoryLifetime(calleeCache);
|
||||
F->verifyMemoryLifetime(calleeCache, &getDeadEndBlocks());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -864,3 +864,11 @@ bb0:
|
||||
%10 = tuple ()
|
||||
return %10
|
||||
}
|
||||
|
||||
sil [ossa] @storage_leaked_into_dead_ends : $@convention(thin) () -> () {
|
||||
%t = apply undef() : $@convention(thin) () -> (@owned T)
|
||||
%t_addr = alloc_stack $T
|
||||
store %t to [init] %t_addr
|
||||
dealloc_stack %t_addr
|
||||
unreachable
|
||||
}
|
||||
|
||||
@@ -1205,39 +1205,6 @@ bb0(%0 : $*T, %1 : $*T, %2 : $*T):
|
||||
return %15 : $()
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @alloc_box_in_specialized_callee :
|
||||
// CHECK-NOT: alloc_box
|
||||
// CHECK-LABEL: } // end sil function 'alloc_box_in_specialized_callee'
|
||||
sil [ossa] @alloc_box_in_specialized_callee : $@convention(thin) (Int) -> () {
|
||||
bb0(%0 : $Int):
|
||||
%1 = alloc_box ${ var Int }
|
||||
%2 = project_box %1, 0
|
||||
store %0 to [trivial] %2
|
||||
%4 = function_ref @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> ()
|
||||
%5 = apply %4(%1) : $@convention(thin) (@guaranteed { var Int }) -> ()
|
||||
destroy_value %1
|
||||
%r = tuple ()
|
||||
return %r
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil shared [ossa] @$s20callee_with_allocboxTf0s_n :
|
||||
// CHECK-NOT: alloc_box
|
||||
// CHECK-LABEL: } // end sil function '$s20callee_with_allocboxTf0s_n'
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @callee_with_allocbox :
|
||||
// CHECK-NOT: alloc_box
|
||||
// CHECK-LABEL: } // end sil function 'callee_with_allocbox'
|
||||
sil [ossa] @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> () {
|
||||
bb0(%0 : @guaranteed ${ var Int }):
|
||||
%1 = alloc_box ${ var Int }
|
||||
%2 = project_box %1 : ${ var Int }, 0
|
||||
%3 = project_box %0 : ${ var Int }, 0
|
||||
copy_addr %3 to %2
|
||||
destroy_value %1
|
||||
%r = tuple ()
|
||||
return %r
|
||||
}
|
||||
|
||||
sil @getC : $@convention(thin) () -> (@owned C)
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @leak_to_inf_loop_1 : {{.*}} {
|
||||
|
||||
Reference in New Issue
Block a user