Support integer_overflow static lib diagnostics.

This extends the minimal runtime dependency mutator to allow signed
and unsigned integer overflow diagnostics in static libraries and
binaries. This also enables the integer_overflow flag for static
libraries and binaries.

Note compilation will fail if the static library is a dependency
of a Make module that does not also have diagnostics enabled.

Bug: 66952339
Bug: 73283972
Test: make SANITIZE_TARGET{,_DIAG}=integer_overflow
Test: Enabled diagnostics in a static lib, saw results in logcat.
Test: Checked showcommands output for ubsan runtime library inclusion.

Change-Id: Ic52881a0f74cdcac0e4a15335df493b59b002ae5
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c9fcafc..859d876 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -115,6 +115,7 @@
 	SanitizerEnabled  bool `blueprint:"mutated"`
 	SanitizeDep       bool `blueprint:"mutated"`
 	MinimalRuntimeDep bool `blueprint:"mutated"`
+	UbsanRuntimeDep   bool `blueprint:"mutated"`
 	InSanitizerDir    bool `blueprint:"mutated"`
 }
 
@@ -199,8 +200,9 @@
 			}
 		}
 
+		// Global integer_overflow builds do not support static libraries.
 		if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
-			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
+			if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) && !ctx.static() {
 				s.Integer_overflow = boolPtr(true)
 			}
 		}
@@ -209,8 +211,9 @@
 			ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
 		}
 
+		// Global integer_overflow builds do not support static library diagnostics.
 		if found, globalSanitizersDiag = removeFromList("integer_overflow", globalSanitizersDiag); found &&
-			s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) {
+			s.Diag.Integer_overflow == nil && Bool(s.Integer_overflow) && !ctx.static() {
 			s.Diag.Integer_overflow = boolPtr(true)
 		}
 
@@ -250,10 +253,14 @@
 		s.Diag.Cfi = nil
 	}
 
-	// Also disable CFI for host builds.
+	// Disable sanitizers that depend on the UBSan runtime for host builds.
 	if ctx.Host() {
 		s.Cfi = nil
 		s.Diag.Cfi = nil
+		s.Misc_undefined = nil
+		s.Undefined = nil
+		s.All_undefined = nil
+		s.Integer_overflow = nil
 	}
 
 	if ctx.staticBinary() {
@@ -305,7 +312,7 @@
 	if ctx.Device() && sanitize.Properties.MinimalRuntimeDep {
 		flags.LdFlags = append(flags.LdFlags, minimalRuntimePath)
 	}
-	if !sanitize.Properties.SanitizerEnabled {
+	if !sanitize.Properties.SanitizerEnabled && !sanitize.Properties.UbsanRuntimeDep {
 		return flags
 	}
 
@@ -416,14 +423,12 @@
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Integer_overflow) {
-		if !ctx.static() {
-			sanitizers = append(sanitizers, "unsigned-integer-overflow")
-			sanitizers = append(sanitizers, "signed-integer-overflow")
-			flags.CFlags = append(flags.CFlags, intOverflowCflags...)
-			if Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) {
-				diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow")
-				diagSanitizers = append(diagSanitizers, "signed-integer-overflow")
-			}
+		sanitizers = append(sanitizers, "unsigned-integer-overflow")
+		sanitizers = append(sanitizers, "signed-integer-overflow")
+		flags.CFlags = append(flags.CFlags, intOverflowCflags...)
+		if Bool(sanitize.Properties.Sanitize.Diag.Integer_overflow) {
+			diagSanitizers = append(diagSanitizers, "unsigned-integer-overflow")
+			diagSanitizers = append(diagSanitizers, "signed-integer-overflow")
 		}
 	}
 
@@ -463,15 +468,20 @@
 		runtimeLibrary = config.AddressSanitizerRuntimeLibrary(ctx.toolchain())
 	} else if Bool(sanitize.Properties.Sanitize.Thread) {
 		runtimeLibrary = config.ThreadSanitizerRuntimeLibrary(ctx.toolchain())
-	} else if len(diagSanitizers) > 0 {
+	} else if len(diagSanitizers) > 0 || sanitize.Properties.UbsanRuntimeDep {
 		runtimeLibrary = config.UndefinedBehaviorSanitizerRuntimeLibrary(ctx.toolchain())
 	}
 
 	if runtimeLibrary != "" {
+		runtimeLibraryPath := "${config.ClangAsanLibDir}/" + runtimeLibrary
+		if !ctx.static() {
+			runtimeLibraryPath = runtimeLibraryPath + ctx.toolchain().ShlibSuffix()
+		} else {
+			runtimeLibraryPath = runtimeLibraryPath + ".a"
+		}
+
 		// ASan runtime library must be the first in the link order.
-		flags.libFlags = append([]string{
-			"${config.ClangAsanLibDir}/" + runtimeLibrary + ctx.toolchain().ShlibSuffix(),
-		}, flags.libFlags...)
+		flags.libFlags = append([]string{runtimeLibraryPath}, flags.libFlags...)
 		sanitize.runtimeLibrary = runtimeLibrary
 
 		// When linking against VNDK, use the vendor variant of the runtime lib
@@ -594,16 +604,21 @@
 }
 
 // Propagate the ubsan minimal runtime dependency when there are integer overflow sanitized static dependencies.
-func minimalRuntimeDepsMutator() func(android.TopDownMutatorContext) {
+func sanitizerRuntimeDepsMutator() 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) {
+						// If a static dependency is built with the minimal runtime,
+						// make sure we include the ubsan minimal runtime.
 						c.sanitize.Properties.MinimalRuntimeDep = true
+					} else if Bool(d.sanitize.Properties.Sanitize.Diag.Integer_overflow) ||
+						len(d.sanitize.Properties.Sanitize.Diag.Misc_undefined) > 0 {
+						// If a static dependency runs with full ubsan diagnostics,
+						// make sure we include the ubsan runtime.
+						c.sanitize.Properties.UbsanRuntimeDep = true
 					}
 				}
 			})