[llvm-bugs] [Bug 37474] New: -fsanitize=cfi-icall inhibits dead code stripping for mixed ThinLTO/native builds

via llvm-bugs llvm-bugs at lists.llvm.org
Tue May 15 12:56:02 PDT 2018


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

            Bug ID: 37474
           Summary: -fsanitize=cfi-icall inhibits dead code stripping for
                    mixed ThinLTO/native builds
           Product: libraries
           Version: trunk
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: Interprocedural Optimizations
          Assignee: vlad at tsyrklevich.net
          Reporter: vlad at tsyrklevich.net
                CC: kcc at google.com, llvm-bugs at lists.llvm.org,
                    peter at pcc.me.uk

This issue is causing the size regression noted in
https://bugs.chromium.org/p/chromium/issues/detail?id=841916 when enabling
-fsanitize=cfi-icall. This regression is caused by 1. nacl_helper pulling in
lots of code it doesn't seem to use and later strips (e.g. ffmpeg), 2. ThinLTO
not being able to determine what is live outside of ThinLTO compiled bitcode
(e.g. in native object files generated from assembly), and 3. LowerTypeTests
emitting references to dead address-taken functions in those native object
files. Normally the dead functions would be removed by -Wl,-gc-sections but
because CFI jumptables can be reached in the liveness analysis the dead
functions referenced by that jumptable are now live.

Here's a simplified example where just having a dead function in a ThinLTO
build address-take a dead function in a native object file will cause the
native object's dead function to be retained:
$ cat bitcode.c 
#include <stdio.h>

void native_dead(void *);
void* bitcode_dead(void) { return &native_dead; }

// Has the same type signature as native_dead
void addr_taken(void *ptr) { }

int main() {
  void *fptr = &addr_taken;
  ((void(*)(void*))fptr)(NULL);
}

$ cat native.c 
void native_dead() { }

$ clang -c -o native.o native.c
$ clang -flto=thin -fvisibility=hidden -fsanitize=cfi-icall -c -o bitcode.o
bitcode.c
$ clang -flto=thin -fvisibility=hidden -fsanitize=cfi-icall -fuse-ld=lld
-Wl,-gc-sections -o exe.icall bitcode.o native.o
$ nm exe.icall | grep dead
00000000002010e0 T native_dead
0000000000201178 t native_dead.cfi_jt

$ clang -flto=thin -fvisibility=hidden -c -o bitcode.o bitcode.c
$ clang -flto=thin -fvisibility=hidden -fuse-ld=lld -Wl,-gc-sections -o
exe.no-icall bitcode.o native.o
$ nm exe.no-icall | grep dead
$

This occurs because even though bitcode_dead is stripped, native_dead is not
removed from CfiFunctionDecls and a CFI jumptable entry is created for it. The
nacl_helper example is more complicated because there can be multiple
references from bitcode objects to native objects that reference bitcode
objects and back that cause multiple native symbols to be retained.

I spoke with Peter and the idea to fix this is to 1. change the ThinLTO summary
information to mark CfiFunctionDecls/CfiFunctionDefs with the function the
reference was created from, 2. change lld to perform a global liveness analysis
before LTO runs using ThinLTO summary information and looking at native objects
and mark dead objects non-prevailing (right now the analysis is local to just
the LTO bitcode objects), and 3. ignore CfiFunctionDecl/CfiFunctionDefs that
come from functions that will be ThinLTO dead stripped (e.g. non-prevailing.)
Implementing #1 and #3 alone should fix the example above, with #2 required to
handle bitcode->native->bitcode->native reference chains.

-- 
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/20180515/e31951af/attachment.html>


More information about the llvm-bugs mailing list