Add minimal-runtime support for integer overflows.

Adds Soong support for -fsanitze-minimal-runtime when using
the integer overflow sanitizers. This makes the crashes due to these
sanitizers less mysterious.

Bug: 64091660
Test: Compiled and checked the generated compiler commands
Test: Checked program that overflows for the abort reason

Change-Id: Ieeceaf6c35c8371592952d3b8b977aefc11601c5
diff --git a/cc/cc.go b/cc/cc.go
index 91bf9a6..ebc98ac 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -52,6 +52,8 @@
 		ctx.TopDown("tsan_deps", sanitizerDepsMutator(tsan))
 		ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
 
+		ctx.TopDown("minimal_runtime_deps", minimalRuntimeDepsMutator())
+
 		ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
 		ctx.TopDown("vndk_deps", sabiDepsMutator)
 
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 471db1d..279ceef 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -215,6 +215,10 @@
 	return SanitizerRuntimeLibrary(t, "ubsan_standalone")
 }
 
+func UndefinedBehaviorSanitizerMinimalRuntimeLibrary(t Toolchain) string {
+	return SanitizerRuntimeLibrary(t, "ubsan_minimal")
+}
+
 func ThreadSanitizerRuntimeLibrary(t Toolchain) string {
 	return SanitizerRuntimeLibrary(t, "tsan")
 }
diff --git a/cc/makevars.go b/cc/makevars.go
index 23910d3..0386f93 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -276,6 +276,7 @@
 		if target.Os.Class == android.Device {
 			ctx.Strict(secondPrefix+"ADDRESS_SANITIZER_RUNTIME_LIBRARY", strings.TrimSuffix(config.AddressSanitizerRuntimeLibrary(toolchain), ".so"))
 			ctx.Strict(secondPrefix+"UBSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain), ".so"))
+			ctx.Strict(secondPrefix+"UBSAN_MINIMAL_RUNTIME_LIBRARY", strings.TrimSuffix(config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(toolchain), ".a"))
 			ctx.Strict(secondPrefix+"TSAN_RUNTIME_LIBRARY", strings.TrimSuffix(config.ThreadSanitizerRuntimeLibrary(toolchain), ".so"))
 		}
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c47c319..535d28f 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -42,7 +42,8 @@
 	cfiExportsMap      android.Path
 	cfiStaticLibsMutex sync.Mutex
 
-	intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
+	intOverflowCflags   = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
+	minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer", "-fno-sanitize-recover=integer"}
 )
 
 type sanitizerType int
@@ -112,9 +113,10 @@
 		Blacklist *string
 	} `android:"arch_variant"`
 
-	SanitizerEnabled bool `blueprint:"mutated"`
-	SanitizeDep      bool `blueprint:"mutated"`
-	InSanitizerDir   bool `blueprint:"mutated"`
+	SanitizerEnabled  bool `blueprint:"mutated"`
+	SanitizeDep       bool `blueprint:"mutated"`
+	MinimalRuntimeDep bool `blueprint:"mutated"`
+	InSanitizerDir    bool `blueprint:"mutated"`
 }
 
 type sanitize struct {
@@ -301,6 +303,11 @@
 }
 
 func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
+	minimalRuntimePath := "${config.ClangAsanLibDir}/" + config.UndefinedBehaviorSanitizerMinimalRuntimeLibrary(ctx.toolchain()) + ".a"
+
+	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
+		flags.LdFlags = append(flags.LdFlags, minimalRuntimePath)
+	}
 	if !sanitize.Properties.SanitizerEnabled {
 		return flags
 	}
@@ -431,6 +438,7 @@
 
 	if len(sanitizers) > 0 {
 		sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",")
+
 		flags.CFlags = append(flags.CFlags, sanitizeArg)
 		if ctx.Host() {
 			flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
@@ -440,6 +448,11 @@
 			_, flags.LdFlags = removeFromList("-Wl,--no-undefined", flags.LdFlags)
 		} else {
 			flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
+
+			if enableMinimalRuntime(sanitize) {
+				flags.CFlags = append(flags.CFlags, strings.Join(minimalRuntimeFlags, " "))
+				flags.libFlags = append([]string{minimalRuntimePath}, flags.libFlags...)
+			}
 		}
 	}
 
@@ -589,6 +602,24 @@
 	}
 }
 
+// Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
+func minimalRuntimeDepsMutator() func(android.TopDownMutatorContext) {
+	return func(mctx android.TopDownMutatorContext) {
+		if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
+			mctx.VisitDepsDepthFirst(func(module android.Module) {
+				if d, ok := module.(*Module); ok && d.static() && d.sanitize != nil {
+
+					// If a static dependency will be built with the minimal runtime,
+					// make sure we include the ubsan minimal runtime.
+					if enableMinimalRuntime(d.sanitize) {
+						c.sanitize.Properties.MinimalRuntimeDep = true
+					}
+				}
+			})
+		}
+	}
+}
+
 // Create sanitized variants for modules that need them
 func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) {
 	return func(mctx android.BottomUpMutatorContext) {
@@ -659,6 +690,18 @@
 	}).(*[]string)
 }
 
+func enableMinimalRuntime(sanitize *sanitize) bool {
+	if !Bool(sanitize.Properties.Sanitize.Address) &&
+		(Bool(sanitize.Properties.Sanitize.Integer_overflow) ||
+			len(sanitize.Properties.Sanitize.Misc_undefined) > 0) &&
+		!(Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
+			Bool(sanitize.Properties.Sanitize.Diag.Cfi) ||
+			len(sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0) {
+		return true
+	}
+	return false
+}
+
 func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
 	cfiStaticLibs := cfiStaticLibs(ctx.Config())
 	sort.Strings(*cfiStaticLibs)