Skip to content

Commit

Permalink
[instcombine] Exploit UB implied by nofree attributes
Browse files Browse the repository at this point in the history
This patch simply implements the documented UB of the current nofree attributes as specified. It doesn't try to be fancy about inference (yet), it just implements the cases already specified and inferred.

Note: When this lands, it may expose miscompiles. If so, please revert and provide a test case. It's likely the bug is in the existing inference code and without a relatively complete test case, it will be hard to debug.

Differential Revision: https://reviews.llvm.org/D96349
  • Loading branch information
preames committed Feb 18, 2021
1 parent 46757cc commit 8666463
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
14 changes: 14 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2799,6 +2799,20 @@ Instruction *InstCombinerImpl::visitFree(CallInst &FI) {
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:
// 1) freeing a pointer which is explicitly nofree
// 2) calling free from a call site marked nofree
// 3) calling free in a function scope marked nofree
if (auto *A = dyn_cast<Argument>(Op->stripPointerCasts()))
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);
return eraseInstFromFunction(FI);
}

// If we optimize for code size, try to move the call to free before the null
// test so that simplify cfg can remove the empty block and dead code
// elimination the branch. I.e., helps to turn something like:
Expand Down
31 changes: 30 additions & 1 deletion llvm/test/Transforms/InstCombine/malloc-free-delete.ll
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ define void @test10() {

define void @test11() {
; CHECK-LABEL: @test11(
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable(8) i8* @_Znwm(i64 8) #7
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable(8) i8* @_Znwm(i64 8) #8
; CHECK-NEXT: call void @_ZdlPv(i8* nonnull [[CALL]])
; CHECK-NEXT: ret void
;
Expand Down Expand Up @@ -390,3 +390,32 @@ if.end: ; preds = %entry, %if.then
ret void
}

; Freeing a no-free pointer -> full UB
define void @test13(i8* nofree %foo) {
; CHECK-LABEL: @test13(
; CHECK-NEXT: store i1 true, i1* undef, align 1
; CHECK-NEXT: ret void
;
call void @free(i8* %foo)
ret void
}

; Freeing a no-free pointer -> full UB
define void @test14(i8* %foo) nofree {
; CHECK-LABEL: @test14(
; CHECK-NEXT: store i1 true, i1* undef, align 1
; CHECK-NEXT: ret void
;
call void @free(i8* %foo)
ret void
}

; free call marked no-free -> full UB
define void @test15(i8* %foo) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: store i1 true, i1* undef, align 1
; CHECK-NEXT: ret void
;
call void @free(i8* %foo) nofree
ret void
}

0 comments on commit 8666463

Please sign in to comment.