init: Add some ASAN helpers

Init is special.

It starts early and does not pick up the Android ASAN options provided
on the environment.  Therefore we pull in /system/asan.options in
explicitly if it exists.  We provide sane defaults that will allow the
system to boot otherwise.

Logging is complicated because it needs to go to the kernel log.
So use sanitizer functions to install log functions.

Bug: 117879229
Test: m && m SANITIZE_TARGET=address
Test: init boots with ASAN enabled
Change-Id: I72c033a1f86ba5d6b2e4f943e7a3acd0d399c8bf
diff --git a/init/init.cpp b/init/init.cpp
index 42ec88c..b12ba8c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -61,6 +61,10 @@
 #include "ueventd.h"
 #include "util.h"
 
+#if __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+#endif
+
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
@@ -74,6 +78,25 @@
 namespace android {
 namespace init {
 
+#if __has_feature(address_sanitizer)
+// Load asan.options if it exists since these are not yet in the environment.
+// Always ensure detect_container_overflow=0 as there are false positives with this check.
+// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
+extern "C" const char* __asan_default_options() {
+    return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
+__sanitizer_report_error_summary(const char* summary) {
+    LOG(ERROR) << "Main stage (error summary): " << summary;
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
+AsanReportCallback(const char* str) {
+    LOG(ERROR) << "Main stage: " << str;
+}
+#endif
+
 static int property_triggers_enabled = 0;
 
 static char qemu[32];
@@ -619,6 +642,10 @@
 }
 
 int main(int argc, char** argv) {
+#if __has_feature(address_sanitizer)
+    __asan_set_error_report_callback(AsanReportCallback);
+#endif
+
     if (!strcmp(basename(argv[0]), "ueventd")) {
         return ueventd_main(argc, argv);
     }