Support memtag sanitizer.

Bug: 295173102
Test: local unit tests
Change-Id: Ib8cd82cd3989d9c120255e149473d8ec00f100f5
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 7f78e28..83553c8 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -851,7 +851,7 @@
 	return ret
 }
 
-// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
+// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module.
 func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
 	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
 	archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
@@ -1936,6 +1936,8 @@
 	sanitizerFeatures := bazel.StringListAttribute{}
 	sanitizerCopts := bazel.StringListAttribute{}
 	sanitizerCompilerInputs := bazel.LabelListAttribute{}
+	memtagFeatures := bazel.StringListAttribute{}
+	memtagFeature := ""
 	bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		var features []string
 		if sanitizerProps, ok := props.(*SanitizeProperties); ok {
@@ -1960,9 +1962,18 @@
 					features = append(features, "android_cfi_assembly_support")
 				}
 			}
+
+			if sanitizerProps.Sanitize.Memtag_heap != nil {
+				if (axis == bazel.NoConfigAxis && memtagFeature == "") ||
+					(axis == bazel.OsArchConfigurationAxis && config == bazel.OsArchAndroidArm64) {
+					memtagFeature = setMemtagValue(sanitizerProps, &memtagFeatures)
+				}
+			}
 			sanitizerFeatures.SetSelectValue(axis, config, features)
 		}
 	})
+	sanitizerFeatures.Append(memtagFeatures)
+
 	return sanitizerValues{
 		features:                 sanitizerFeatures,
 		copts:                    sanitizerCopts,
@@ -1970,6 +1981,26 @@
 	}
 }
 
+func setMemtagValue(sanitizerProps *SanitizeProperties, memtagFeatures *bazel.StringListAttribute) string {
+	var features []string
+	if proptools.Bool(sanitizerProps.Sanitize.Memtag_heap) {
+		features = append(features, "memtag_heap")
+	} else {
+		features = append(features, "-memtag_heap")
+	}
+	// Logic comes from: https://cs.android.com/android/platform/superproject/main/+/32ea1afbd1148b0b78553f24fa61116c999eb968:build/soong/cc/sanitize.go;l=910
+	if sanitizerProps.Sanitize.Diag.Memtag_heap != nil {
+		if proptools.Bool(sanitizerProps.Sanitize.Diag.Memtag_heap) {
+			features = append(features, "diag_memtag_heap")
+		} else {
+			features = append(features, "-diag_memtag_heap")
+		}
+	}
+	memtagFeatures.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, features)
+
+	return features[0]
+}
+
 func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
 	lto_feature_name := "android_thin_lto"
 	ltoBoolFeatures := bazel.BoolAttribute{}
diff --git a/cc/test.go b/cc/test.go
index adc80c2..c643862 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -720,6 +720,21 @@
 		}
 	}
 
+	// The logic comes from https://cs.android.com/android/platform/superproject/main/+/0df8153267f96da877febc5332240fa06ceb8533:build/soong/cc/sanitize.go;l=488
+	var features bazel.StringListAttribute
+	curFeatures := testBinaryAttrs.binaryAttributes.Features.SelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64)
+	var newFeatures []string
+	if !android.InList("memtag_heap", curFeatures) && !android.InList("-memtag_heap", curFeatures) {
+		newFeatures = append(newFeatures, "memtag_heap")
+		if !android.InList("diag_memtag_heap", curFeatures) && !android.InList("-diag_memtag_heap", curFeatures) {
+			newFeatures = append(newFeatures, "diag_memtag_heap")
+		}
+	}
+
+	features.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, newFeatures)
+	testBinaryAttrs.binaryAttributes.Features.Append(features)
+	testBinaryAttrs.binaryAttributes.Features.DeduplicateAxesFromBase()
+
 	m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
 
 	testBinary := m.linker.(*testBinary)