if (isa<ConstantPointerNull>(Op))
return eraseInstFromFunction(FI);
- // If we free a pointer we've been explicitly told won't be freed, this
- // would be full UB and thus we can conclude this is unreachable. Cases:
+
+ // If we free a non-null pointer we've been explicitly told won't be freed,
+ // this would be full UB and thus we can conclude that the argument must
+ // be null at the point of the free. Cases:
// 1) freeing a pointer which is explicitly nofree
// 2) calling free from a call site marked nofree (TODO: can generalize
// for non-arguments)
if (A->hasAttribute(Attribute::NoFree) ||
FI.hasFnAttr(Attribute::NoFree) ||
FI.getFunction()->hasFnAttribute(Attribute::NoFree)) {
- // Leave a marker since we can't modify the CFG here.
- CreateNonTerminatorUnreachable(&FI);
+ Value *Null = ConstantPointerNull::get(cast<PointerType>(A->getType()));
+ Value *Cond = Builder.CreateICmpEQ(A, Null);
+ Builder.CreateAssumption(Cond);
return eraseInstFromFunction(FI);
}
ret void
}
-; Freeing a no-free pointer -> full UB
+; Freeing a no-free pointer -> %foo must be null
define void @test13(i8* nofree %foo) {
; CHECK-LABEL: @test13(
-; CHECK-NEXT: store i1 true, i1* undef, align 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
; CHECK-NEXT: ret void
;
call void @free(i8* %foo)
ret void
}
-; Freeing a no-free pointer -> full UB
+; Freeing a no-free pointer -> %foo must be null
define void @test14(i8* %foo) nofree {
; CHECK-LABEL: @test14(
-; CHECK-NEXT: store i1 true, i1* undef, align 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
; CHECK-NEXT: ret void
;
call void @free(i8* %foo)
ret void
}
-; free call marked no-free -> full UB
+; free call marked no-free -> %foo must be null
define void @test15(i8* %foo) {
; CHECK-LABEL: @test15(
-; CHECK-NEXT: store i1 true, i1* undef, align 1
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null
+; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]])
; CHECK-NEXT: ret void
;
call void @free(i8* %foo) nofree
ret void
}
+
+; freeing a nonnull nofree pointer -> full UB
+define void @test16(i8* nonnull nofree %foo) {
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: call void @llvm.assume(i1 false)
+; CHECK-NEXT: ret void
+;
+ call void @free(i8* %foo)
+ ret void
+}