From acceedb15f52108d0e36d8090cb25fcdf34a4fc1 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Fri, 16 Aug 2019 23:10:34 +0000 Subject: [PATCH] [CodeGenPrepare] Fix use-after-free MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit If OptimizeExtractBits() encountered a shift instruction with no operands at all, it would erase the instruction, but still return false. This previously didn’t matter because its caller would always return after processing the instruction, but https://reviews.llvm.org/D63233 changed the function’s caller to fall through if it returned false, which would then cause a use-after-free detectable by ASAN. This change makes OptimizeExtractBits return true if it removes a shift instruction with no users, terminating processing of the instruction. Patch by: @brentdax (Brent Royal-Gordon) Differential Revision: https://reviews.llvm.org/D66330 llvm-svn: 369168 --- llvm/lib/CodeGen/CodeGenPrepare.cpp | 3 ++- .../Transforms/CodeGenPrepare/sink-shift-and-trunc.ll | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index d4d5fcd..7da810c 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1682,10 +1682,11 @@ static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI, TheUse = InsertedShift; } - // If we removed all uses, nuke the shift. + // If we removed all uses, or there are none, nuke the shift. if (ShiftI->use_empty()) { salvageDebugInfo(*ShiftI); ShiftI->eraseFromParent(); + MadeChange = true; } return MadeChange; diff --git a/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll b/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll index 07ea73b..929a4f4 100644 --- a/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll +++ b/llvm/test/Transforms/CodeGenPrepare/sink-shift-and-trunc.ll @@ -58,6 +58,23 @@ return: ; preds = %if.then17, %if.end1 ret i32 %retval.0, !dbg !63 } +; CodeGenPrepare was erasing the unused lshr instruction, but then further +; processing the instruction after it was freed. If this bug is still present, +; this test will always crash in an LLVM built with ASAN enabled, and may +; crash even if ASAN is not enabled. + +define i32 @shift_unused(i32 %a) { +; CHECK-LABEL: @shift_unused( +; CHECK-NEXT: BB2: +; CHECK-NEXT: ret i32 [[A:%.*]] +; + %as = lshr i32 %a, 3 + br label %BB2 + +BB2: + ret i32 %a +} + ; CHECK: [[shift1_loc]] = !DILocation(line: 1 ; CHECK: [[trunc1_loc]] = !DILocation(line: 2 ; CHECK: [[shift2_loc]] = !DILocation(line: 3 -- 2.7.4