google / sanitizers

AddressSanitizer, ThreadSanitizer, MemorySanitizer
Other
11.52k stars 1.04k forks source link

asan and ubsan open together trigger a linking error #842

Closed butterl closed 6 years ago

butterl commented 7 years ago

I tried build with asan and ubsan both on in my test module with Android.bp:

cc_binary {
    name: "ubsan_test",

    clang: true,
    sanitize: {
        all_undefined: true,
        address: true,
        diag: {
            undefined: true,
        },
    },
    clang_cflags: [
        "-g",
        "-Wall",
        "-Werror",
        "-std=gnu++11",
        "-Wno-missing-field-initializers",
        "-O0",
    ],

    srcs:["Test_san.cc"], 
}

And got error while linking , it seems got none ubsan lib during the lib

[ 28% 2/7] //system/ub_test:ubsan_test link ubsan_test
FAILED: out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test
prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ out/soong/.intermediates/bionic/libc/crtbegin_dynamic/android_arm64_armv8-a_core/crtbegin_dynamic.o @out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test.rsp prebuilts/clang/host/linux-x86/clang-4053586/lib64/clang/5.0/lib/linux/libclang_rt.asan-aarch64-android.so out/soong/.intermediates/external/compiler-rt/lib/asan/libasan/android_arm64_armv8-a_static_core/libasan.a -Wl,--start-group out/soong/.intermediates/external/compiler-rt/libcompiler_rt-extras/android_arm64_armv8-a_static_core/libcompiler_rt-extras.a out/soong/.intermediates/build/soong/libatomic/android_arm64_armv8-a_static_core/libatomic.a out/soong/.intermediates/build/soong/libgcc/android_arm64_armv8-a_static_core/libgcc.a -Wl,--end-group out/soong/.intermediates/external/libcxx/libc++/android_arm64_armv8-a_shared_core/libc++.so out/soong/.intermediates/bionic/libdl/libdl/android_arm64_armv8-a_shared_core/libdl.so out/soong/.intermediates/bionic/libc/libc/android_arm64_armv8-a_shared_core/libc.so out/soong/.intermediates/bionic/libm/libm/android_arm64_armv8-a_shared_core/libm.so out/soong/.intermediates/bionic/libdl/libdl/android_arm64_armv8-a_shared_core/libdl.so out/soong/.intermediates/bionic/libc/crtend_android/android_arm64_armv8-a_core/obj/bionic/libc/arch-common/bionic/crtend.o -o out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test -target aarch64-linux-android -Bprebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/bin -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--build-id=md5 -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,-maarch64linux -Wl,--hash-style=gnu -Wl,--fix-cortex-a53-843419 -fuse-ld=gold -Wl,--icf=safe -Wl,--no-undefined-version  -pie -nostdlib -Bdynamic -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-u,__asan_preinit  -Wl,-dynamic-linker,/system/bin/linker_asan64
**system/ub_test/Test_san.cc:15: error: undefined reference to '__ubsan_handle_add_overflow'**
clang.real: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.

Seems the code block in build/soong/cc/sanitize.go makes the runtime lib only goes to address branch

    // Link a runtime library if needed.
    runtimeLibrary := ""
    if Bool(sanitize.Properties.Sanitize.Address) { 
        runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
    } else if len(diagSanitizers) > 0 {
        runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+     fmt.Println("debug  diagSanitizers:",diagSanitizers)
    }

    if runtimeLibrary != "" {
        // ASan runtime library must be the first in the link order.
        flags.libFlags = append([]string{
            "${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
        }, flags.libFlags...)
        sanitize.runtimeLibrary = runtimeLibrary
+     fmt.Println("debug  runtimeLibrary:",runtimeLibrary)
        // When linking against VNDK, use the vendor variant of the runtime lib
        sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary
        if ctx.vndk() {
            sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + vendorSuffix
        }
    }

The output is only the asan , someone got good idea for this?

debug  runtimeLibrary: libclang_rt.asan-aarch64-android
debug  runtimeLibrary: libclang_rt.asan-aarch64-android
debug  runtimeLibrary: libclang_rt.asan-arm-android
butterl commented 7 years ago

some updates:

workaround to get ubsan and asan branch all called ,but get linking error on asan

diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1fcb32c..b20ce1d 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -414,10 +414,17 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {

        // Link a runtime library if needed.
        runtimeLibrary := ""
-       if Bool(sanitize.Properties.Sanitize.Address) {
+       if Bool(sanitize.Properties.Sanitize.All_undefined) {
+               runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+               fmt.Println("All_undefined diagSanitizers:",diagSanitizers)
+               fmt.Println("All_undefined diagSanitizers len",len(diagSanitizers))
+       }else if Bool(sanitize.Properties.Sanitize.Address) {
+               fmt.Println("diagSanitizers:",diagSanitizers)
+               fmt.Println("diagSanitizers len:",len(diagSanitizers))
                runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
        } else if len(diagSanitizers) > 0 {
                runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+               fmt.Println("butter diagSanitizers:",diagSanitizers)
        }

        if runtimeLibrary != "" {
@@ -426,7 +433,7 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
                        "${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
                }, flags.libFlags...)
                sanitize.runtimeLibrary = runtimeLibrary
-
+        fmt.Println("runtimeLibrary got:",runtimeLibrary)
                // When linking against VNDK, use the vendor variant of the runtime lib
                sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary
                if ctx.vndk() {

Output error log,

diagSanitizers: [address]
diagSanitizers len: 1
diagSanitizers: [address]
diagSanitizers len: 1
All_undefined diagSanitizers: [undefined address]
All_undefined diagSanitizers len 2
runtimeLibrary got: libclang_rt.ubsan_standalone-aarch64-android
diagSanitizers: [address]
diagSanitizers len: 1
runtimeLibrary got: libclang_rt.asan-aarch64-android
diagSanitizers: [address]
diagSanitizers len: 1
runtimeLibrary got: libclang_rt.asan-arm-android
.......
[ 28% 2/7] //system/ub_test:ubsan_test link ubsan_test
FAILED: out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test
prebuilts/clang/host/linux-x86/clang-4053586/bin/clang++ out/soong/.intermediates/bionic/libc/crtbegin_dynamic/android_arm64_armv8-a_core/crtbegin_dynamic.o @out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test.rsp prebuilts/clang/host/linux-x86/clang-4053586/lib64/clang/5.0/lib/linux/libclang_rt.ubsan_standalone-aarch64-android.so out/soong/.intermediates/external/compiler-rt/lib/asan/libasan/android_arm64_armv8-a_static_core/libasan.a -Wl,--start-group out/soong/.intermediates/external/compiler-rt/libcompiler_rt-extras/android_arm64_armv8-a_static_core/libcompiler_rt-extras.a out/soong/.intermediates/build/soong/libatomic/android_arm64_armv8-a_static_core/libatomic.a out/soong/.intermediates/build/soong/libgcc/android_arm64_armv8-a_static_core/libgcc.a -Wl,--end-group out/soong/.intermediates/external/libcxx/libc++/android_arm64_armv8-a_shared_core/libc++.so out/soong/.intermediates/bionic/libdl/libdl/android_arm64_armv8-a_shared_core/libdl.so out/soong/.intermediates/bionic/libc/libc/android_arm64_armv8-a_shared_core/libc.so out/soong/.intermediates/bionic/libm/libm/android_arm64_armv8-a_shared_core/libm.so out/soong/.intermediates/bionic/libdl/libdl/android_arm64_armv8-a_shared_core/libdl.so out/soong/.intermediates/bionic/libc/crtend_android/android_arm64_armv8-a_core/obj/bionic/libc/arch-common/bionic/crtend.o -o out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/ubsan_test -target aarch64-linux-android -Bprebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/aarch64-linux-android/bin -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--build-id=md5 -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,-maarch64linux -Wl,--hash-style=gnu -Wl,--fix-cortex-a53-843419 -fuse-ld=gold -Wl,--icf=safe -Wl,--no-undefined-version  -pie -nostdlib -Bdynamic -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-u,__asan_preinit  -Wl,-dynamic-linker,/system/bin/linker_asan64
out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/obj/system/ub_test/Test_san.o:system/ub_test/Test_san.cc:function asan.module_ctor: error: undefined reference to '__asan_init'
out/soong/.intermediates/system/ub_test/ubsan_test/android_arm64_armv8-a_core_asan/obj/system/ub_test/Test_san.o:system/ub_test/Test_san.cc:function asan.module_ctor: error: undefined reference to '__asan_version_mismatch_check_v8'
clang.real: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
09:11:29 ninja failed with: exit status 1

I notice a comments in the script,but not sure if this is the reason , for this function has being called several time, someone got idea how to deal with it?

        // **ASan runtime library must be the first in the link order.**
        flags.libFlags = append([]string{
            "${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
        }, flags.libFlags...)
eugenis commented 7 years ago

This looks like a problem with toolchain prebuilts. ASan runtime library, when built upstream (with LLVM's CMake build system) exports the entire UBSan interface.

butterl commented 7 years ago

Some updates:

I tried workaround patch like below, runtimeLibrary1 is ugly but works when diagSanitizers = [undefined address] , a temp var to add the second flag to the finall sanitize.androidMkRuntimeLibrary

diff --git a/cc/sanitize.go b/cc/sanitize.go
index 1fcb32c..f8db676 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -414,24 +414,50 @@ func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {

    // Link a runtime library if needed.
    runtimeLibrary := ""
-   if Bool(sanitize.Properties.Sanitize.Address) {
-       runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
-   } else if len(diagSanitizers) > 0 {
-       runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+   runtimeLibrary1 := ""
+   if len(diagSanitizers) > 1 {
+       fmt.Println("Debug diagSanitizers:",diagSanitizers)
+       if Bool(sanitize.Properties.Sanitize.All_undefined) {
+           runtimeLibrary1 = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+       }
+       if Bool(sanitize.Properties.Sanitize.Address) {
+           runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
+       }
+   } else {
+       if Bool(sanitize.Properties.Sanitize.Address) {
+           runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
+       } else if len(diagSanitizers) > 0 {
+           runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
+       }
    }

    if runtimeLibrary != "" {
+       if runtimeLibrary1 != "" {
+           flags.libFlags = append([]string{
+              "${config.ClangAsanLibDir}/" + runtimeLibrary1 + ctx.toolchain().ShlibSuffix(),
+           }, flags.libFlags...)
+       }
+
        // ASan runtime library must be the first in the link order.
        flags.libFlags = append([]string{
            "${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
        }, flags.libFlags...)
+
        sanitize.runtimeLibrary = runtimeLibrary
+       fmt.Println("runtimeLibrary got:",sanitize.runtimeLibrary)

        // When linking against VNDK, use the vendor variant of the runtime lib
        sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary
        if ctx.vndk() {
            sanitize.androidMkRuntimeLibrary = sanitize.runtimeLibrary + vendorSuffix
+           if runtimeLibrary1 != "" {
+               sanitize.androidMkRuntimeLibrary += " " + runtimeLibrary1 + vendorSuffix
+           }
+       } else {
+           fmt.Println("=== new path enter")
+           sanitize.androidMkRuntimeLibrary += " " + runtimeLibrary1
        }
+       fmt.Println("===sanitize.androidMkRuntimeLibrary got:",sanitize.androidMkRuntimeLibrary)
    }

    blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)

Finally got all so in build.ninja, @eugenis do you got any better solution for this?

libFlags = ${g.config.ClangAsanLibDir}/libclang_rt.asan-aarch64-android.so ${g.config.ClangAsanLibDir}/libclang_rt.ubsan_standalone-aarch64-android.so out/soong/.intermediates/ex ternal/compiler-rt/lib/asan/libasan/android_arm64_armv8-a_static_core/libasan.a -Wl,--start-group out/soong/.intermediates/external/compiler-rt/libcompiler_rt-extras/android_arm64_ar mv8-a_static_core/libcompiler_rt-extras.a out/soong/.intermediates/build/soong/libatomic/android_arm64_armv8-a_static_core/libatomic.a out/soong/.intermediates/build/soong/libgcc/and roid_arm64_armv8-a_static_core/libgcc.a -Wl,--end-group out/soong/.intermediates/external/libcxx/libc++/android_arm64_armv8-a_shared_core/libc++.so out/soong/.intermediates/bionic/li bdl/libdl/android_arm64_armv8-a_shared_core/libdl.so out/soong/.intermediates/bionic/libc/libc/android_arm64_armv8-a_shared_core/libc.so out/soong/.intermediates/bionic/libm/libm/and roid_arm64_armv8-a_shared_core/libm.so out/soong/.intermediates/bionic/libdl/libdl/android_arm64_armv8-a_shared_core/libdl.so

eugenis commented 7 years ago

If linking 2 libraries works for you - great, but it could be slightly broken because it runs parts of library initialization twice. The next toolchain update is expected to have correct prebuilts and will not need this change.

butterl commented 7 years ago

@eugenis When will we expected to get the next toolchain update, and new toolchain also get new checking point in sanitizers right?

eugenis commented 7 years ago

Do you mean new types of checks in sanitizers? Maybe. It will be an update to a newer revision of LLVM which includes new sanitizers. I don't know when it will happen.

If you want, as a local workaround, you can try building libclang_rt.asan* libraries from upstream LLVM sources. They should be compatible with the compiler in the current Android toolchain. This is the script that does that on the buildbot: https://github.com/llvm-mirror/zorg/blob/master/zorg/buildbot/builders/sanitizers/buildbot_android_functions.sh#L69

On Wed, Aug 2, 2017 at 6:58 PM, butterl notifications@github.com wrote:

@eugenis https://github.com/eugenis When will we expected to get the next toolchain update, and new toolchain also get new checking point in sanitizers right?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/google/sanitizers/issues/842#issuecomment-319846576, or mute the thread https://github.com/notifications/unsubscribe-auth/AAZuSluO0hy4gNyk2tOF0ZIczfKndFnLks5sUSkogaJpZM4OoWZ8 .