android studio address sanitizer using build.gradle

a 夏天 提交于 2019-12-03 22:15:17

So after a bit of struggle, I have used the method described in https://virtualrealitypop.com/oreo-ndk-secrets-7d075a9b084. I have added a new sanitize_debug target in my build.gradle with the following:

tasks.whenTaskAdded { task ->
    if (task.name == 'generateSanitize_debugBuildConfig') {
        task.dependsOn createWrapScriptAddDir
    }
}

task deleteASAN(type: Delete) {
    delete 'jni/sanitizer/'
}

static def writeWrapScriptToFullyCompileJavaApp(wrapFile, abi) {
    if(abi == "armeabi" || abi == "armeabi-v7a")
        abi = "arm"
    if(abi == "arm64-v8a")
        abi = "aarch64"
    if (abi == "x86")
        abi = "i686"
    wrapFile.withWriter { writer ->
        writer.write('#!/system/bin/sh\n')
        writer.write('HERE="$(cd "$(dirname "$0")" && pwd)"\n')
        writer.write('export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1\n')
        writer.write('export ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.b\n')
        writer.write("export LD_PRELOAD=\$HERE/libclang_rt.asan-${abi}-android.so\n")
        writer.write('\$@\n')
    }
}


task copyASANLibs {
    def libDirs = android.ndkDirectory.absolutePath + "/toolchains/llvm/prebuilt/"

    for (String abi : rootProject.ext.abiFilters) {
        def destDir = new File("wizards/src/sanitize_debug/jniLibs/" + abi)
        destDir.mkdirs()

        def renamedAbi = abi
        if(abi == "armeabi-v7a" || abi == "armeabi")
            renamedAbi = "arm"
        if(abi == "arm64-v8a")
            renamedAbi = "aarch64"
        if (abi == "x86")
            renamedAbi = "i686"


        FileTree tree = fileTree(dir: libDirs).include("**/*asan*${renamedAbi}*.so")
        tree.each { File file ->
            copy {
                from file
                into destDir.absolutePath
            }
        }
    }
}
task createWrapScriptAddDir(dependsOn: copyASANLibs) {
    for (String abi : rootProject.ext.abiFilters) {
        def dir = new File("wizards/src/sanitize_debug/resources/lib/" + abi)
        dir.mkdirs()
        def wrapFile = new File(dir, "wrap.sh")
        wrapFile.setExecutable(true, false)
        writeWrapScriptToFullyCompileJavaApp(wrapFile, abi)
    }
}

The things that needs to be improved are

1°) the cleanup phase when switching to a non sanitized build must be called manually,

2°) The wrapper script is built and packaged for all arm architectures, which is a workaround the fact that you can't easily specify a target architecture for the wrap.sh scrip (see bug https://issuetracker.google.com/issues/74058603)

In order to also debug you can adjust the answer from downstroy and tweak wrap.sh script, since the simple version of wrap.sh will prevent debugging ( from https://developer.android.com/ndk/guides/wrap-script ) :

        writer.write('#!/system/bin/sh\n')
        writer.write('HERE="$(cd "$(dirname "$0")" && pwd)"\n')
        writer.write('export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1\n')
        writer.write('export ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.b\n')
        writer.write("export LD_PRELOAD=\$HERE/libclang_rt.asan-${abi}-android.so\n")
        writer.write('cmd=$1\n')
        writer.write('shift\n')
        writer.write('os_version=$(getprop ro.build.version.sdk)\n')
        writer.write('if [ "$os_version" -eq "27" ]; then\n')
        writer.write('cmd="$cmd -Xrunjdwp:transport=dt_android_adb,suspend=n,server=y -Xcompiler-option --debuggable $@"\n')
        writer.write('elif [ "$os_version" -eq "28" ]; then\n')
        writer.write('cmd="$cmd -XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y -Xcompiler-option --debuggable $@"\n')
        writer.write('else\n')
        writer.write('cmd="$cmd -XjdwpProvider:adbconnection $@"\n')
        writer.write('fi\n')
        writer.write('exec $cmd\n')
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!