[StackSafety] Fix union which produces wrapped sets

This commit is contained in:
Vitaly Buka 2020-08-08 02:05:04 -07:00
parent a6feeb1c6b
commit dee812a297
2 changed files with 56 additions and 18 deletions

View File

@ -61,6 +61,32 @@ static cl::opt<bool> StackSafetyRun("stack-safety-run", cl::init(false),
namespace {
// Check if we should bailout for such ranges.
bool isUnsafe(const ConstantRange &R) {
return R.isEmptySet() || R.isFullSet() || R.isUpperSignWrapped();
}
ConstantRange addOverflowNever(const ConstantRange &L, const ConstantRange &R) {
assert(!L.isSignWrappedSet());
assert(!R.isSignWrappedSet());
if (L.signedAddMayOverflow(R) !=
ConstantRange::OverflowResult::NeverOverflows)
return ConstantRange::getFull(L.getBitWidth());
ConstantRange Result = L.add(R);
assert(!Result.isSignWrappedSet());
return Result;
}
ConstantRange unionNoWrap(const ConstantRange &L, const ConstantRange &R) {
assert(!L.isSignWrappedSet());
assert(!R.isSignWrappedSet());
auto Result = L.unionWith(R);
// Two non-wrapped sets can produce wrapped.
if (Result.isSignWrappedSet())
Result = ConstantRange::getFull(Result.getBitWidth());
return Result;
}
/// Describes use of address in as a function call argument.
template <typename CalleeTy> struct CallInfo {
/// Function being called.
@ -93,11 +119,7 @@ template <typename CalleeTy> struct UseInfo {
UseInfo(unsigned PointerSize) : Range{PointerSize, false} {}
void updateRange(const ConstantRange &R) {
assert(!R.isUpperSignWrapped());
Range = Range.unionWith(R);
assert(!Range.isUpperSignWrapped());
}
void updateRange(const ConstantRange &R) { Range = unionNoWrap(Range, R); }
};
template <typename CalleeTy>
@ -108,18 +130,6 @@ raw_ostream &operator<<(raw_ostream &OS, const UseInfo<CalleeTy> &U) {
return OS;
}
// Check if we should bailout for such ranges.
bool isUnsafe(const ConstantRange &R) {
return R.isEmptySet() || R.isFullSet() || R.isUpperSignWrapped();
}
ConstantRange addOverflowNever(const ConstantRange &L, const ConstantRange &R) {
if (L.signedAddMayOverflow(R) !=
ConstantRange::OverflowResult::NeverOverflows)
return ConstantRange(L.getBitWidth(), true);
return L.add(R);
}
/// Calculate the allocation size of a given alloca. Returns empty range
// in case of confution.
ConstantRange getStaticAllocaSizeRange(const AllocaInst &AI) {
@ -515,7 +525,7 @@ bool StackSafetyDataFlowAnalysis<CalleeTy>::updateOneUse(UseInfo<CalleeTy> &US,
if (UpdateToFullSet)
US.Range = UnknownRange;
else
US.Range = US.Range.unionWith(CalleeRange);
US.updateRange(CalleeRange);
}
}
return Changed;

View File

@ -11,6 +11,7 @@ target triple = "x86_64-unknown-linux-gnu"
declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
declare void @llvm.memset.p0i8.i64(i8* %dest, i8 %val, i64 %len, i1 %isvolatile)
; Address leaked.
define void @LeakAddress() {
@ -81,6 +82,33 @@ entry:
ret void
}
define dso_local void @WriteMinMax(i8* %p) {
; CHECK-LABEL: @WriteMinMax{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: full-set
; CHECK-NEXT: allocas uses:
; CHECK-EMPTY:
entry:
%p1 = getelementptr i8, i8* %p, i64 9223372036854775805
store i8 0, i8* %p1, align 1
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775805
store i8 0, i8* %p2, align 1
ret void
}
define dso_local void @WriteMax(i8* %p) {
; CHECK-LABEL: @WriteMax{{$}}
; CHECK-NEXT: args uses:
; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)
; CHECK-NEXT: allocas uses:
; CHECK-EMPTY:
entry:
call void @llvm.memset.p0i8.i64(i8* %p, i8 1, i64 9223372036854775806, i1 0)
%p2 = getelementptr i8, i8* %p, i64 -9223372036854775807
call void @llvm.memset.p0i8.i64(i8* %p2, i8 1, i64 9223372036854775806, i1 0)
ret void
}
define void @StoreOutOfBounds() {
; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
; CHECK-NEXT: args uses: