[llvm-bugs] [Bug 34383] New: [SPGO] Crash when the sample profile loader promotes an indirect call

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Aug 30 11:18:25 PDT 2017


https://bugs.llvm.org/show_bug.cgi?id=34383

            Bug ID: 34383
           Summary: [SPGO] Crash when the sample profile loader promotes
                    an indirect call
           Product: new-bugs
           Version: trunk
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: new bugs
          Assignee: unassignedbugs at nondot.org
          Reporter: rob.lougher at gmail.com
                CC: llvm-bugs at lists.llvm.org

Compiling the following program and profile results in a crash:

========== test.c ================
float foo(int i) { return 5; }

int bar(int (*f)(int)) {
  return (*f)(5);
}
==================================

====== prof.txt ======
bar:1:1
 1: foo:1
======================

$ clang -O2 -fprofile-sample-use=prof.txt test.c

#0 0x0000000003facc75 llvm::sys::PrintStackTrace(llvm::raw_ostream&)
/llvm/lib/Support/Unix/Signals.inc:398:0
#1 0x0000000003facd08 PrintStackTraceSignalHandler(void*)
/llvm/lib/Support/Unix/Signals.inc:462:0
#2 0x0000000003faaf4f llvm::sys::RunSignalHandlers()
/llvm/lib/Support/Signals.cpp:49:0
#3 0x0000000003fac4ea SignalHandler(int)
/llvm/lib/Support/Unix/Signals.inc:252:0
#4 0x00007f34458a9390 __restore_rt
(/lib/x86_64-linux-gnu/libpthread.so.0+0x11390)
#5 0x0000000001eeecfe llvm::Instruction::getParent()
/llvm/include/llvm/IR/Instruction.h:67:0
#6 0x0000000003ffca3f llvm::InlineFunction(llvm::CallSite,
llvm::InlineFunctionInfo&, llvm::AAResults*, bool)
/llvm/lib/Transforms/Utils/InlineFunction.cpp:1460:0
#7 0x00000000039d471d (anonymous
namespace)::SampleProfileLoader::inlineHotFunctions(llvm::Function&,
llvm::DenseSet<unsigned long, llvm::DenseMapInfo<unsigned long> >&)
/llvm/lib/Transforms/IPO/SampleProfile.cpp:748:0
#8 0x00000000039d762a (anonymous
namespace)::SampleProfileLoader::emitAnnotations(llvm::Function&)
/llvm/lib/Transforms/IPO/SampleProfile.cpp:1362:0
#9 0x00000000039d8731 (anonymous
namespace)::SampleProfileLoader::runOnFunction(llvm::Function&,
llvm::AnalysisManager<llvm::Module>*) /llvm/lib/Transforms/IPO/SampleProfil
e.cpp:1500:0
...

The problem occurs within the sample profile loader.  When it sees an indirect
call it tries to promote it using the call targets from the sample data. This
involves creating a direct and an indirect call path guarded with a target
check.  After promoting the call it then inlines the direct function call in
order to apply the sample.

According to the sample profile the indirect call target was the function
foo().  The call is promoted as follows:

== Basic Block Before ==

entry:
  %call = call i32 %f(i32 5), !dbg !9
  ret i32 %call, !dbg !10


== Basic Blocks After ==

entry:
  %0 = bitcast i32 (i32)* %f to i8*, !dbg !9
  %1 = icmp eq i8* %0, bitcast (float (i32)* @foo to i8*), !dbg !9
  br i1 %1, label %if.true.direct_targ, label %if.false.orig_indirect, !dbg !9,
!prof !10

if.true.direct_targ:                              ; preds = %entry
  %2 = call float @foo(i32 5), !dbg !9
  %3 = bitcast float %2 to i32
  br label %if.end.icp, !dbg !9

if.false.orig_indirect:                           ; preds = %entry
  %call = call i32 %f(i32 5), !dbg !9
  br label %if.end.icp, !dbg !9

if.end.icp:                                       ; preds =
%if.false.orig_indirect, %if.true.direct_targ
  %4 = phi i32 [ %call, %if.false.orig_indirect ], [ %3, %if.true.direct_targ ]
  ret i32 %4, !dbg !11
==========================

Note the direct call path (if.true.direct_targ) has a direct call to foo().

What causes the crash is the mismatch in return types between the indirect call
and foo().  Normally, the utility function that promoted the call
(promoteIndirectCall) returns a reference to the direct call instruction. 
However, the return type mismatch has caused a cast to be inserted from
float->int, and promoteIndirectCall() instead returns a reference to the cast.

A later change in r294205 modified the code so that any pointer casts were
skipped (via stripPointerCasts).  However, in this case we have a non-pointer
cast which is not skipped, and we end up trying to inline a cast instruction...

So how did we end up with a return type mismatch?  The example was manually
constructed from scratch after investigating a real-life crash.  It could
theoretically occur due to profile corruption or use of an out-of-date profile.
 However, in this case, the crash occured in the following circumstances:

1) a source line contained two calls (one indirect and one direct)
2) the sampled binary was compiled with -g only (i.e. without
-fdebug-info-for-profiling)
3) "by luck" the sample didn't capture any targets for the indirect call, only
for the direct call.

As the program was compiled without -fdebug-info-for-profiling no
discriminators were present.  This meant the sample for the direct call matched
when the sample loader looked for the indirect call targets, resulting in a
wrong function being found.

A less than ideal fix for the problem would be to abandon inlining of the
function if after skipping pointer casts we did not have a call instruction. 
This is less than ideal because we would still have promoted the indirect call
to a wrong function.  However, it is benign as the target guard means the
indirect path will always be taken.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20170830/2e567ad3/attachment.html>


More information about the llvm-bugs mailing list