| // Copyright 2021 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package cc | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"runtime" | 
 | 	"strings" | 
 | 	"testing" | 
 |  | 
 | 	"android/soong/android" | 
 |  | 
 | 	"github.com/google/blueprint" | 
 | ) | 
 |  | 
 | var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(` | 
 | 	cc_library_shared { | 
 | 		name: "libclang_rt.asan", | 
 | 		host_supported: true, | 
 | 	} | 
 | 	cc_library_static { | 
 | 		name: "libclang_rt.asan.static", | 
 | 		host_supported: true, | 
 | 	} | 
 | 	cc_library_static { | 
 | 		name: "libclang_rt.asan_cxx.static", | 
 | 		host_supported: true, | 
 | 	} | 
 | `)) | 
 |  | 
 | var prepareForTsanTest = android.FixtureAddFile("tsan/Android.bp", []byte(` | 
 | 	cc_library_shared { | 
 | 		name: "libclang_rt.tsan", | 
 | 		host_supported: true, | 
 | 	} | 
 | `)) | 
 |  | 
 | type providerInterface interface { | 
 | 	ModuleProvider(blueprint.Module, blueprint.ProviderKey) interface{} | 
 | } | 
 |  | 
 | // expectSharedLinkDep verifies that the from module links against the to module as a | 
 | // shared library. | 
 | func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { | 
 | 	t.Helper() | 
 | 	fromLink := from.Description("link") | 
 | 	toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo) | 
 |  | 
 | 	if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); !android.InList(w, g) { | 
 | 		t.Errorf("%s should link against %s, expected %q, got %q", | 
 | 			from.Module(), to.Module(), w, g) | 
 | 	} | 
 | } | 
 |  | 
 | // expectNoSharedLinkDep verifies that the from module links against the to module as a | 
 | // shared library. | 
 | func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { | 
 | 	t.Helper() | 
 | 	fromLink := from.Description("link") | 
 | 	toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo) | 
 |  | 
 | 	if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); android.InList(w, g) { | 
 | 		t.Errorf("%s should not link against %s, expected %q, got %q", | 
 | 			from.Module(), to.Module(), w, g) | 
 | 	} | 
 | } | 
 |  | 
 | // expectStaticLinkDep verifies that the from module links against the to module as a | 
 | // static library. | 
 | func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { | 
 | 	t.Helper() | 
 | 	fromLink := from.Description("link") | 
 | 	toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo) | 
 |  | 
 | 	if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); !android.InList(w, g) { | 
 | 		t.Errorf("%s should link against %s, expected %q, got %q", | 
 | 			from.Module(), to.Module(), w, g) | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | // expectNoStaticLinkDep verifies that the from module links against the to module as a | 
 | // static library. | 
 | func expectNoStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) { | 
 | 	t.Helper() | 
 | 	fromLink := from.Description("link") | 
 | 	toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo) | 
 |  | 
 | 	if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); android.InList(w, g) { | 
 | 		t.Errorf("%s should not link against %s, expected %q, got %q", | 
 | 			from.Module(), to.Module(), w, g) | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | // expectInstallDep verifies that the install rule of the from module depends on the | 
 | // install rule of the to module. | 
 | func expectInstallDep(t *testing.T, from, to android.TestingModule) { | 
 | 	t.Helper() | 
 | 	fromInstalled := from.Description("install") | 
 | 	toInstalled := to.Description("install") | 
 |  | 
 | 	// combine implicits and order-only dependencies, host uses implicit but device uses | 
 | 	// order-only. | 
 | 	got := append(fromInstalled.Implicits.Strings(), fromInstalled.OrderOnly.Strings()...) | 
 | 	want := toInstalled.Output.String() | 
 | 	if !android.InList(want, got) { | 
 | 		t.Errorf("%s installation should depend on %s, expected %q, got %q", | 
 | 			from.Module(), to.Module(), want, got) | 
 | 	} | 
 | } | 
 |  | 
 | type expectedRuntimeLinkage int | 
 |  | 
 | const ( | 
 | 	RUNTIME_LINKAGE_NONE   = expectedRuntimeLinkage(0) | 
 | 	RUNTIME_LINKAGE_SHARED = iota | 
 | 	RUNTIME_LINKAGE_STATIC | 
 | ) | 
 |  | 
 | func TestAsan(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	bp := ` | 
 | 		cc_binary { | 
 | 			name: "bin_with_asan", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 				"libasan", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnoasan", | 
 | 				"libstatic_asan", | 
 | 			], | 
 | 			sanitize: { | 
 | 				address: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "bin_no_asan", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 				"libasan", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnoasan", | 
 | 				"libstatic_asan", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libshared", | 
 | 			host_supported: true, | 
 | 			shared_libs: ["libtransitive"], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libasan", | 
 | 			host_supported: true, | 
 | 			shared_libs: ["libtransitive"], | 
 | 			sanitize: { | 
 | 				address: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libtransitive", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libstatic", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libnoasan", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				address: false, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libstatic_asan", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				address: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 	` | 
 |  | 
 | 	preparer := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 		prepareForAsanTest, | 
 | 	) | 
 | 	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() | 
 |  | 
 | 	check := func(t *testing.T, variant string, runtimeLinkage expectedRuntimeLinkage, preparer android.FixturePreparer) { | 
 | 		result := preparer.RunTestWithBp(t, bp) | 
 | 		ctx := result.TestContext | 
 | 		asanVariant := variant + "_asan" | 
 | 		sharedVariant := variant + "_shared" | 
 | 		sharedAsanVariant := sharedVariant + "_asan" | 
 | 		staticVariant := variant + "_static" | 
 | 		staticAsanVariant := staticVariant + "_asan" | 
 |  | 
 | 		// The binaries, one with asan and one without | 
 | 		binWithAsan := result.ModuleForTests("bin_with_asan", asanVariant) | 
 | 		binNoAsan := result.ModuleForTests("bin_no_asan", variant) | 
 |  | 
 | 		// Shared libraries that don't request asan | 
 | 		libShared := result.ModuleForTests("libshared", sharedVariant) | 
 | 		libTransitive := result.ModuleForTests("libtransitive", sharedVariant) | 
 |  | 
 | 		// Shared library that requests asan | 
 | 		libAsan := result.ModuleForTests("libasan", sharedAsanVariant) | 
 |  | 
 | 		// Static library that uses an asan variant for bin_with_asan and a non-asan variant | 
 | 		// for bin_no_asan. | 
 | 		libStaticAsanVariant := result.ModuleForTests("libstatic", staticAsanVariant) | 
 | 		libStaticNoAsanVariant := result.ModuleForTests("libstatic", staticVariant) | 
 |  | 
 | 		// Static library that never uses asan. | 
 | 		libNoAsan := result.ModuleForTests("libnoasan", staticVariant) | 
 |  | 
 | 		// Static library that specifies asan | 
 | 		libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant) | 
 | 		libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant) | 
 |  | 
 | 		libAsanSharedRuntime := result.ModuleForTests("libclang_rt.asan", sharedVariant) | 
 | 		libAsanStaticRuntime := result.ModuleForTests("libclang_rt.asan.static", staticVariant) | 
 | 		libAsanStaticCxxRuntime := result.ModuleForTests("libclang_rt.asan_cxx.static", staticVariant) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binWithAsan, libShared) | 
 | 		expectSharedLinkDep(t, ctx, binWithAsan, libAsan) | 
 | 		expectSharedLinkDep(t, ctx, libShared, libTransitive) | 
 | 		expectSharedLinkDep(t, ctx, libAsan, libTransitive) | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binWithAsan, libStaticAsanVariant) | 
 | 		expectStaticLinkDep(t, ctx, binWithAsan, libNoAsan) | 
 | 		expectStaticLinkDep(t, ctx, binWithAsan, libStaticAsan) | 
 |  | 
 | 		expectInstallDep(t, binWithAsan, libShared) | 
 | 		expectInstallDep(t, binWithAsan, libAsan) | 
 | 		expectInstallDep(t, binWithAsan, libTransitive) | 
 | 		expectInstallDep(t, libShared, libTransitive) | 
 | 		expectInstallDep(t, libAsan, libTransitive) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binNoAsan, libShared) | 
 | 		expectSharedLinkDep(t, ctx, binNoAsan, libAsan) | 
 | 		expectSharedLinkDep(t, ctx, libShared, libTransitive) | 
 | 		expectSharedLinkDep(t, ctx, libAsan, libTransitive) | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binNoAsan, libStaticNoAsanVariant) | 
 | 		expectStaticLinkDep(t, ctx, binNoAsan, libNoAsan) | 
 | 		expectStaticLinkDep(t, ctx, binNoAsan, libStaticAsanNoAsanVariant) | 
 |  | 
 | 		expectInstallDep(t, binNoAsan, libShared) | 
 | 		expectInstallDep(t, binNoAsan, libAsan) | 
 | 		expectInstallDep(t, binNoAsan, libTransitive) | 
 | 		expectInstallDep(t, libShared, libTransitive) | 
 | 		expectInstallDep(t, libAsan, libTransitive) | 
 |  | 
 | 		if runtimeLinkage == RUNTIME_LINKAGE_SHARED { | 
 | 			expectSharedLinkDep(t, ctx, binWithAsan, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, binNoAsan, libAsanSharedRuntime) | 
 | 			expectSharedLinkDep(t, ctx, libAsan, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, libShared, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, libTransitive, libAsanSharedRuntime) | 
 | 		} else { | 
 | 			expectNoSharedLinkDep(t, ctx, binWithAsan, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, binNoAsan, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, libAsan, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, libShared, libAsanSharedRuntime) | 
 | 			expectNoSharedLinkDep(t, ctx, libTransitive, libAsanSharedRuntime) | 
 | 		} | 
 |  | 
 | 		if runtimeLinkage == RUNTIME_LINKAGE_STATIC { | 
 | 			expectStaticLinkDep(t, ctx, binWithAsan, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, binNoAsan, libAsanStaticRuntime) | 
 | 			expectStaticLinkDep(t, ctx, libAsan, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libShared, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libTransitive, libAsanStaticRuntime) | 
 |  | 
 | 			expectStaticLinkDep(t, ctx, binWithAsan, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, binNoAsan, libAsanStaticCxxRuntime) | 
 | 			expectStaticLinkDep(t, ctx, libAsan, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libShared, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libTransitive, libAsanStaticCxxRuntime) | 
 | 		} else { | 
 | 			expectNoStaticLinkDep(t, ctx, binWithAsan, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, binNoAsan, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libAsan, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libShared, libAsanStaticRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libTransitive, libAsanStaticRuntime) | 
 |  | 
 | 			expectNoStaticLinkDep(t, ctx, binWithAsan, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, binNoAsan, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libAsan, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libShared, libAsanStaticCxxRuntime) | 
 | 			expectNoStaticLinkDep(t, ctx, libTransitive, libAsanStaticCxxRuntime) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	t.Run("host", func(t *testing.T) { check(t, buildOS, RUNTIME_LINKAGE_NONE, preparer) }) | 
 | 	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", RUNTIME_LINKAGE_SHARED, preparer) }) | 
 | 	t.Run("host musl", func(t *testing.T) { | 
 | 		check(t, "linux_musl_x86_64", RUNTIME_LINKAGE_STATIC, | 
 | 			android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl)) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestTsan(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	bp := ` | 
 | 	cc_binary { | 
 | 		name: "bin_with_tsan", | 
 | 		host_supported: true, | 
 | 		shared_libs: [ | 
 | 			"libshared", | 
 | 			"libtsan", | 
 | 		], | 
 | 		sanitize: { | 
 | 			thread: true, | 
 | 		} | 
 | 	} | 
 |  | 
 | 	cc_binary { | 
 | 		name: "bin_no_tsan", | 
 | 		host_supported: true, | 
 | 		shared_libs: [ | 
 | 			"libshared", | 
 | 			"libtsan", | 
 | 		], | 
 | 	} | 
 |  | 
 | 	cc_library_shared { | 
 | 		name: "libshared", | 
 | 		host_supported: true, | 
 | 		shared_libs: ["libtransitive"], | 
 | 	} | 
 |  | 
 | 	cc_library_shared { | 
 | 		name: "libtsan", | 
 | 		host_supported: true, | 
 | 		shared_libs: ["libtransitive"], | 
 | 		sanitize: { | 
 | 			thread: true, | 
 | 		} | 
 | 	} | 
 |  | 
 | 	cc_library_shared { | 
 | 		name: "libtransitive", | 
 | 		host_supported: true, | 
 | 	} | 
 | ` | 
 |  | 
 | 	preparer := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 		prepareForTsanTest, | 
 | 	) | 
 | 	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() | 
 |  | 
 | 	check := func(t *testing.T, variant string, preparer android.FixturePreparer) { | 
 | 		result := preparer.RunTestWithBp(t, bp) | 
 | 		ctx := result.TestContext | 
 | 		tsanVariant := variant + "_tsan" | 
 | 		sharedVariant := variant + "_shared" | 
 | 		sharedTsanVariant := sharedVariant + "_tsan" | 
 |  | 
 | 		// The binaries, one with tsan and one without | 
 | 		binWithTsan := result.ModuleForTests("bin_with_tsan", tsanVariant) | 
 | 		binNoTsan := result.ModuleForTests("bin_no_tsan", variant) | 
 |  | 
 | 		// Shared libraries that don't request tsan | 
 | 		libShared := result.ModuleForTests("libshared", sharedVariant) | 
 | 		libTransitive := result.ModuleForTests("libtransitive", sharedVariant) | 
 |  | 
 | 		// Shared library that requests tsan | 
 | 		libTsan := result.ModuleForTests("libtsan", sharedTsanVariant) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binWithTsan, libShared) | 
 | 		expectSharedLinkDep(t, ctx, binWithTsan, libTsan) | 
 | 		expectSharedLinkDep(t, ctx, libShared, libTransitive) | 
 | 		expectSharedLinkDep(t, ctx, libTsan, libTransitive) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binNoTsan, libShared) | 
 | 		expectSharedLinkDep(t, ctx, binNoTsan, libTsan) | 
 | 		expectSharedLinkDep(t, ctx, libShared, libTransitive) | 
 | 		expectSharedLinkDep(t, ctx, libTsan, libTransitive) | 
 | 	} | 
 |  | 
 | 	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) }) | 
 | 	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) }) | 
 | 	t.Run("host musl", func(t *testing.T) { | 
 | 		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl)) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestMiscUndefined(t *testing.T) { | 
 | 	if runtime.GOOS != "linux" { | 
 | 		t.Skip("requires linux") | 
 | 	} | 
 |  | 
 | 	t.Parallel() | 
 | 	bp := ` | 
 | 	cc_binary { | 
 | 		name: "bin_with_ubsan", | 
 | 		srcs: ["src.cc"], | 
 | 		host_supported: true, | 
 | 		static_libs: [ | 
 | 			"libstatic", | 
 | 			"libubsan", | 
 | 		], | 
 | 		sanitize: { | 
 | 			misc_undefined: ["integer"], | 
 | 		} | 
 | 	} | 
 |  | 
 | 	cc_binary { | 
 | 		name: "bin_no_ubsan", | 
 | 		host_supported: true, | 
 | 		srcs: ["src.cc"], | 
 | 		static_libs: [ | 
 | 			"libstatic", | 
 | 			"libubsan", | 
 | 		], | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "libstatic", | 
 | 		host_supported: true, | 
 | 		srcs: ["src.cc"], | 
 | 		static_libs: ["libtransitive"], | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "libubsan", | 
 | 		host_supported: true, | 
 | 		srcs: ["src.cc"], | 
 | 		whole_static_libs: ["libtransitive"], | 
 | 		sanitize: { | 
 | 			misc_undefined: ["integer"], | 
 | 		} | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "libtransitive", | 
 | 		host_supported: true, | 
 | 		srcs: ["src.cc"], | 
 | 	} | 
 | ` | 
 |  | 
 | 	preparer := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 	) | 
 | 	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() | 
 |  | 
 | 	check := func(t *testing.T, variant string, preparer android.FixturePreparer) { | 
 | 		result := preparer.RunTestWithBp(t, bp) | 
 | 		ctx := result.TestContext | 
 | 		staticVariant := variant + "_static" | 
 |  | 
 | 		// The binaries, one with ubsan and one without | 
 | 		binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) | 
 | 		binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) | 
 |  | 
 | 		// Static libraries that don't request ubsan | 
 | 		libStatic := result.ModuleForTests("libstatic", staticVariant) | 
 | 		libTransitive := result.ModuleForTests("libtransitive", staticVariant) | 
 |  | 
 | 		libUbsan := result.ModuleForTests("libubsan", staticVariant) | 
 |  | 
 | 		libUbsanMinimal := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binWithUbsan, libStatic) | 
 | 		expectStaticLinkDep(t, ctx, binWithUbsan, libUbsan) | 
 | 		expectStaticLinkDep(t, ctx, binWithUbsan, libUbsanMinimal) | 
 |  | 
 | 		miscUndefinedSanFlag := "-fsanitize=integer" | 
 | 		binWithUbsanCflags := binWithUbsan.Rule("cc").Args["cFlags"] | 
 | 		if !strings.Contains(binWithUbsanCflags, miscUndefinedSanFlag) { | 
 | 			t.Errorf("'bin_with_ubsan' Expected %q to be in flags %q, was not", miscUndefinedSanFlag, binWithUbsanCflags) | 
 | 		} | 
 | 		libStaticCflags := libStatic.Rule("cc").Args["cFlags"] | 
 | 		if strings.Contains(libStaticCflags, miscUndefinedSanFlag) { | 
 | 			t.Errorf("'libstatic' Expected %q to NOT be in flags %q, was", miscUndefinedSanFlag, binWithUbsanCflags) | 
 | 		} | 
 | 		libUbsanCflags := libUbsan.Rule("cc").Args["cFlags"] | 
 | 		if !strings.Contains(libUbsanCflags, miscUndefinedSanFlag) { | 
 | 			t.Errorf("'libubsan' Expected %q to be in flags %q, was not", miscUndefinedSanFlag, binWithUbsanCflags) | 
 | 		} | 
 | 		libTransitiveCflags := libTransitive.Rule("cc").Args["cFlags"] | 
 | 		if strings.Contains(libTransitiveCflags, miscUndefinedSanFlag) { | 
 | 			t.Errorf("'libtransitive': Expected %q to NOT be in flags %q, was", miscUndefinedSanFlag, binWithUbsanCflags) | 
 | 		} | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binNoUbsan, libStatic) | 
 | 		expectStaticLinkDep(t, ctx, binNoUbsan, libUbsan) | 
 | 	} | 
 |  | 
 | 	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) }) | 
 | 	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) }) | 
 | 	t.Run("host musl", func(t *testing.T) { | 
 | 		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl)) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestFuzz(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	bp := ` | 
 | 		cc_binary { | 
 | 			name: "bin_with_fuzzer", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 				"libfuzzer", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnofuzzer", | 
 | 				"libstatic_fuzzer", | 
 | 			], | 
 | 			sanitize: { | 
 | 				fuzzer: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "bin_no_fuzzer", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 				"libfuzzer", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnofuzzer", | 
 | 				"libstatic_fuzzer", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libshared", | 
 | 			host_supported: true, | 
 | 			shared_libs: ["libtransitive"], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libfuzzer", | 
 | 			host_supported: true, | 
 | 			shared_libs: ["libtransitive"], | 
 | 			sanitize: { | 
 | 				fuzzer: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libtransitive", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libstatic", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libnofuzzer", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				fuzzer: false, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libstatic_fuzzer", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 	` | 
 |  | 
 | 	result := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 	).RunTestWithBp(t, bp) | 
 |  | 
 | 	check := func(t *testing.T, result *android.TestResult, variant string) { | 
 | 		ctx := result.TestContext | 
 | 		fuzzerVariant := variant + "_fuzzer" | 
 | 		sharedVariant := variant + "_shared" | 
 | 		sharedFuzzerVariant := sharedVariant + "_fuzzer" | 
 | 		staticVariant := variant + "_static" | 
 | 		staticFuzzerVariant := staticVariant + "_fuzzer" | 
 |  | 
 | 		// The binaries, one with fuzzer and one without | 
 | 		binWithFuzzer := result.ModuleForTests("bin_with_fuzzer", fuzzerVariant) | 
 | 		binNoFuzzer := result.ModuleForTests("bin_no_fuzzer", variant) | 
 |  | 
 | 		// Shared libraries that don't request fuzzer | 
 | 		libShared := result.ModuleForTests("libshared", sharedVariant) | 
 | 		libTransitive := result.ModuleForTests("libtransitive", sharedVariant) | 
 |  | 
 | 		// Shared libraries that don't request fuzzer | 
 | 		libSharedFuzzer := result.ModuleForTests("libshared", sharedFuzzerVariant) | 
 | 		libTransitiveFuzzer := result.ModuleForTests("libtransitive", sharedFuzzerVariant) | 
 |  | 
 | 		// Shared library that requests fuzzer | 
 | 		libFuzzer := result.ModuleForTests("libfuzzer", sharedFuzzerVariant) | 
 |  | 
 | 		// Static library that uses an fuzzer variant for bin_with_fuzzer and a non-fuzzer variant | 
 | 		// for bin_no_fuzzer. | 
 | 		libStaticFuzzerVariant := result.ModuleForTests("libstatic", staticFuzzerVariant) | 
 | 		libStaticNoFuzzerVariant := result.ModuleForTests("libstatic", staticVariant) | 
 |  | 
 | 		// Static library that never uses fuzzer. | 
 | 		libNoFuzzer := result.ModuleForTests("libnofuzzer", staticVariant) | 
 |  | 
 | 		// Static library that specifies fuzzer | 
 | 		libStaticFuzzer := result.ModuleForTests("libstatic_fuzzer", staticFuzzerVariant) | 
 | 		libStaticFuzzerNoFuzzerVariant := result.ModuleForTests("libstatic_fuzzer", staticVariant) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binWithFuzzer, libSharedFuzzer) | 
 | 		expectSharedLinkDep(t, ctx, binWithFuzzer, libFuzzer) | 
 | 		expectSharedLinkDep(t, ctx, libSharedFuzzer, libTransitiveFuzzer) | 
 | 		expectSharedLinkDep(t, ctx, libFuzzer, libTransitiveFuzzer) | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binWithFuzzer, libStaticFuzzerVariant) | 
 | 		expectStaticLinkDep(t, ctx, binWithFuzzer, libNoFuzzer) | 
 | 		expectStaticLinkDep(t, ctx, binWithFuzzer, libStaticFuzzer) | 
 |  | 
 | 		expectSharedLinkDep(t, ctx, binNoFuzzer, libShared) | 
 | 		expectSharedLinkDep(t, ctx, binNoFuzzer, libFuzzer) | 
 | 		expectSharedLinkDep(t, ctx, libShared, libTransitive) | 
 | 		expectSharedLinkDep(t, ctx, libFuzzer, libTransitiveFuzzer) | 
 |  | 
 | 		expectStaticLinkDep(t, ctx, binNoFuzzer, libStaticNoFuzzerVariant) | 
 | 		expectStaticLinkDep(t, ctx, binNoFuzzer, libNoFuzzer) | 
 | 		expectStaticLinkDep(t, ctx, binNoFuzzer, libStaticFuzzerNoFuzzerVariant) | 
 | 	} | 
 |  | 
 | 	t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") }) | 
 | } | 
 |  | 
 | func TestUbsan(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	if runtime.GOOS != "linux" { | 
 | 		t.Skip("requires linux") | 
 | 	} | 
 |  | 
 | 	bp := ` | 
 | 		cc_binary { | 
 | 			name: "bin_with_ubsan", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnoubsan", | 
 | 			], | 
 | 			sanitize: { | 
 | 				undefined: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "bin_depends_ubsan_static", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libubsan", | 
 | 				"libnoubsan", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "bin_depends_ubsan_shared", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libsharedubsan", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "bin_no_ubsan", | 
 | 			host_supported: true, | 
 | 			shared_libs: [ | 
 | 				"libshared", | 
 | 			], | 
 | 			static_libs: [ | 
 | 				"libstatic", | 
 | 				"libnoubsan", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "static_bin_with_ubsan_dep", | 
 | 			static_executable: true, | 
 | 			host_supported: true, | 
 | 			static_libs: [ | 
 | 				"libubsan_diag", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libshared", | 
 | 			host_supported: true, | 
 | 			shared_libs: ["libtransitive"], | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libtransitive", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_shared { | 
 | 			name: "libsharedubsan", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				undefined: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libubsan", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				undefined: true, | 
 | 			} | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libubsan_diag", | 
 | 			host_supported: true, | 
 | 			sanitize: { | 
 | 				undefined: true, | 
 | 				diag: { | 
 | 					undefined: true, | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libstatic", | 
 | 			host_supported: true, | 
 | 		} | 
 |  | 
 | 		cc_library_static { | 
 | 			name: "libnoubsan", | 
 | 			host_supported: true, | 
 | 		} | 
 | 	` | 
 |  | 
 | 	preparer := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 	) | 
 | 	buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() | 
 |  | 
 | 	check := func(t *testing.T, variant string, preparer android.FixturePreparer) { | 
 | 		result := preparer.RunTestWithBp(t, bp) | 
 | 		staticVariant := variant + "_static" | 
 | 		sharedVariant := variant + "_shared" | 
 |  | 
 | 		minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) | 
 | 		standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant) | 
 |  | 
 | 		// The binaries, one with ubsan and one without | 
 | 		binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) | 
 | 		binDependsUbsan := result.ModuleForTests("bin_depends_ubsan_static", variant) | 
 | 		libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant) | 
 | 		binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant) | 
 | 		binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) | 
 | 		staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs", | 
 | 			strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "), | 
 | 			minimalRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_depends_ubsan_static static libs", | 
 | 			strings.Split(binDependsUbsan.Rule("ld").Args["libFlags"], " "), | 
 | 			minimalRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in libsharedubsan static libs", | 
 | 			strings.Split(libSharedUbsan.Rule("ld").Args["libFlags"], " "), | 
 | 			minimalRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 		android.AssertStringListDoesNotContain(t, "unexpected libclang_rt.ubsan_minimal in bin_depends_ubsan_shared static libs", | 
 | 			strings.Split(binDependsUbsanShared.Rule("ld").Args["libFlags"], " "), | 
 | 			minimalRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 		android.AssertStringListDoesNotContain(t, "unexpected libclang_rt.ubsan_minimal in bin_no_ubsan static libs", | 
 | 			strings.Split(binNoUbsan.Rule("ld").Args["libFlags"], " "), | 
 | 			minimalRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_with_ubsan", | 
 | 			strings.Split(binWithUbsan.Rule("ld").Args["ldFlags"], " "), | 
 | 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in bin_depends_ubsan_static static libs", | 
 | 			strings.Split(binDependsUbsan.Rule("ld").Args["ldFlags"], " "), | 
 | 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing -Wl,--exclude-libs for minimal runtime in libsharedubsan static libs", | 
 | 			strings.Split(libSharedUbsan.Rule("ld").Args["ldFlags"], " "), | 
 | 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) | 
 |  | 
 | 		android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_depends_ubsan_shared static libs", | 
 | 			strings.Split(binDependsUbsanShared.Rule("ld").Args["ldFlags"], " "), | 
 | 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) | 
 |  | 
 | 		android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs", | 
 | 			strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "), | 
 | 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) | 
 |  | 
 | 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_standalone.static in static_bin_with_ubsan_dep static libs", | 
 | 			strings.Split(staticBin.Rule("ld").Args["libFlags"], " "), | 
 | 			standaloneRuntime.OutputFiles(t, "")[0].String()) | 
 |  | 
 | 	} | 
 |  | 
 | 	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) }) | 
 | 	t.Run("device", func(t *testing.T) { check(t, "android_arm64_armv8-a", preparer) }) | 
 | 	t.Run("host musl", func(t *testing.T) { | 
 | 		check(t, "linux_musl_x86_64", android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl)) | 
 | 	}) | 
 | } | 
 |  | 
 | type MemtagNoteType int | 
 |  | 
 | const ( | 
 | 	None MemtagNoteType = iota + 1 | 
 | 	Sync | 
 | 	Async | 
 | ) | 
 |  | 
 | func (t MemtagNoteType) str() string { | 
 | 	switch t { | 
 | 	case None: | 
 | 		return "none" | 
 | 	case Sync: | 
 | 		return "sync" | 
 | 	case Async: | 
 | 		return "async" | 
 | 	default: | 
 | 		panic("type_note_invalid") | 
 | 	} | 
 | } | 
 |  | 
 | func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNoteType) { | 
 | 	t.Helper() | 
 |  | 
 | 	found := None | 
 | 	ldFlags := m.Rule("ld").Args["ldFlags"] | 
 | 	if strings.Contains(ldFlags, "-fsanitize-memtag-mode=async") { | 
 | 		found = Async | 
 | 	} else if strings.Contains(ldFlags, "-fsanitize-memtag-mode=sync") { | 
 | 		found = Sync | 
 | 	} | 
 |  | 
 | 	if found != expected { | 
 | 		t.Errorf("Wrong Memtag note in target %q: found %q, expected %q", m.Module().(*Module).Name(), found.str(), expected.str()) | 
 | 	} | 
 | } | 
 |  | 
 | var prepareForTestWithMemtagHeap = android.GroupFixturePreparers( | 
 | 	android.FixtureModifyMockFS(func(fs android.MockFS) { | 
 | 		templateBp := ` | 
 | 		cc_test { | 
 | 			name: "unset_test_%[1]s", | 
 | 			gtest: false, | 
 | 		} | 
 |  | 
 | 		cc_test { | 
 | 			name: "no_memtag_test_%[1]s", | 
 | 			gtest: false, | 
 | 			sanitize: { memtag_heap: false }, | 
 | 		} | 
 |  | 
 | 		cc_test { | 
 | 			name: "set_memtag_test_%[1]s", | 
 | 			gtest: false, | 
 | 			sanitize: { memtag_heap: true }, | 
 | 		} | 
 |  | 
 | 		cc_test { | 
 | 			name: "set_memtag_set_async_test_%[1]s", | 
 | 			gtest: false, | 
 | 			sanitize: { memtag_heap: true, diag: { memtag_heap: false }  }, | 
 | 		} | 
 |  | 
 | 		cc_test { | 
 | 			name: "set_memtag_set_sync_test_%[1]s", | 
 | 			gtest: false, | 
 | 			sanitize: { memtag_heap: true, diag: { memtag_heap: true }  }, | 
 | 		} | 
 |  | 
 | 		cc_test { | 
 | 			name: "unset_memtag_set_sync_test_%[1]s", | 
 | 			gtest: false, | 
 | 			sanitize: { diag: { memtag_heap: true }  }, | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "unset_binary_%[1]s", | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "no_memtag_binary_%[1]s", | 
 | 			sanitize: { memtag_heap: false }, | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "set_memtag_binary_%[1]s", | 
 | 			sanitize: { memtag_heap: true }, | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "set_memtag_set_async_binary_%[1]s", | 
 | 			sanitize: { memtag_heap: true, diag: { memtag_heap: false }  }, | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "set_memtag_set_sync_binary_%[1]s", | 
 | 			sanitize: { memtag_heap: true, diag: { memtag_heap: true }  }, | 
 | 		} | 
 |  | 
 | 		cc_binary { | 
 | 			name: "unset_memtag_set_sync_binary_%[1]s", | 
 | 			sanitize: { diag: { memtag_heap: true }  }, | 
 | 		} | 
 | 		` | 
 | 		subdirNoOverrideBp := fmt.Sprintf(templateBp, "no_override") | 
 | 		subdirOverrideDefaultDisableBp := fmt.Sprintf(templateBp, "override_default_disable") | 
 | 		subdirSyncBp := fmt.Sprintf(templateBp, "override_default_sync") | 
 | 		subdirAsyncBp := fmt.Sprintf(templateBp, "override_default_async") | 
 |  | 
 | 		fs.Merge(android.MockFS{ | 
 | 			"subdir_no_override/Android.bp":              []byte(subdirNoOverrideBp), | 
 | 			"subdir_override_default_disable/Android.bp": []byte(subdirOverrideDefaultDisableBp), | 
 | 			"subdir_sync/Android.bp":                     []byte(subdirSyncBp), | 
 | 			"subdir_async/Android.bp":                    []byte(subdirAsyncBp), | 
 | 		}) | 
 | 	}), | 
 | 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 		variables.MemtagHeapExcludePaths = []string{"subdir_override_default_disable"} | 
 | 		// "subdir_override_default_disable" is covered by both include and override_default_disable paths. override_default_disable wins. | 
 | 		variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync", "subdir_override_default_disable"} | 
 | 		variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async", "subdir_override_default_disable"} | 
 | 	}), | 
 | ) | 
 |  | 
 | func TestSanitizeMemtagHeap(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	variant := "android_arm64_armv8-a" | 
 |  | 
 | 	result := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 		prepareForTestWithMemtagHeap, | 
 | 	).RunTest(t) | 
 | 	ctx := result.TestContext | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	// should sanitize: { diag: { memtag: true } } result in Sync instead of None here? | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	// should sanitize: { diag: { memtag: true } } result in Sync instead of None here? | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) | 
 | } | 
 |  | 
 | func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	variant := "android_arm64_armv8-a" | 
 |  | 
 | 	result := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 		prepareForTestWithMemtagHeap, | 
 | 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 			variables.SanitizeDevice = []string{"memtag_heap"} | 
 | 		}), | 
 | 	).RunTest(t) | 
 | 	ctx := result.TestContext | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	// should sanitize: { diag: { memtag: true } } result in Sync instead of None here? | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) | 
 | } | 
 |  | 
 | func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { | 
 | 	t.Parallel() | 
 | 	variant := "android_arm64_armv8-a" | 
 |  | 
 | 	result := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 		prepareForTestWithMemtagHeap, | 
 | 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 			variables.SanitizeDevice = []string{"memtag_heap"} | 
 | 			variables.SanitizeDeviceDiag = []string{"memtag_heap"} | 
 | 		}), | 
 | 	).RunTest(t) | 
 | 	ctx := result.TestContext | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) | 
 | 	// should sanitize: { diag: { memtag: true } } result in Sync instead of None here? | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) | 
 |  | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) | 
 | 	checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) | 
 | } | 
 |  | 
 | func TestCfi(t *testing.T) { | 
 | 	t.Parallel() | 
 |  | 
 | 	bp := ` | 
 | 	cc_library_shared { | 
 | 		name: "shared_with_cfi", | 
 | 		static_libs: [ | 
 | 			"static_dep_with_cfi", | 
 | 			"static_dep_no_cfi", | 
 | 		], | 
 | 		sanitize: { | 
 | 			cfi: true, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	cc_library_shared { | 
 | 		name: "shared_no_cfi", | 
 | 		static_libs: [ | 
 | 			"static_dep_with_cfi", | 
 | 			"static_dep_no_cfi", | 
 | 		], | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "static_dep_with_cfi", | 
 | 		sanitize: { | 
 | 			cfi: true, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "static_dep_no_cfi", | 
 | 	} | 
 |  | 
 | 	cc_library_shared { | 
 | 		name: "shared_rdep_no_cfi", | 
 | 		static_libs: ["static_dep_with_cfi_2"], | 
 | 	} | 
 |  | 
 | 	cc_library_static { | 
 | 		name: "static_dep_with_cfi_2", | 
 | 		sanitize: { | 
 | 			cfi: true, | 
 | 		}, | 
 | 	} | 
 | ` | 
 | 	preparer := android.GroupFixturePreparers( | 
 | 		prepareForCcTest, | 
 | 	) | 
 | 	result := preparer.RunTestWithBp(t, bp) | 
 | 	ctx := result.TestContext | 
 |  | 
 | 	buildOs := "android_arm64_armv8-a" | 
 | 	shared_suffix := "_shared" | 
 | 	cfi_suffix := "_cfi" | 
 | 	static_suffix := "_static" | 
 |  | 
 | 	sharedWithCfiLib := result.ModuleForTests("shared_with_cfi", buildOs+shared_suffix+cfi_suffix) | 
 | 	sharedNoCfiLib := result.ModuleForTests("shared_no_cfi", buildOs+shared_suffix) | 
 | 	staticWithCfiLib := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix) | 
 | 	staticWithCfiLibCfiVariant := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix+cfi_suffix) | 
 | 	staticNoCfiLib := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix) | 
 | 	staticNoCfiLibCfiVariant := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix+cfi_suffix) | 
 | 	sharedRdepNoCfi := result.ModuleForTests("shared_rdep_no_cfi", buildOs+shared_suffix) | 
 | 	staticDepWithCfi2Lib := result.ModuleForTests("static_dep_with_cfi_2", buildOs+static_suffix) | 
 |  | 
 | 	// Confirm assumptions about propagation of CFI enablement | 
 | 	expectStaticLinkDep(t, ctx, sharedWithCfiLib, staticWithCfiLibCfiVariant) | 
 | 	expectStaticLinkDep(t, ctx, sharedNoCfiLib, staticWithCfiLib) | 
 | 	expectStaticLinkDep(t, ctx, sharedWithCfiLib, staticNoCfiLibCfiVariant) | 
 | 	expectStaticLinkDep(t, ctx, sharedNoCfiLib, staticNoCfiLib) | 
 | 	expectStaticLinkDep(t, ctx, sharedRdepNoCfi, staticDepWithCfi2Lib) | 
 |  | 
 | 	// Confirm that non-CFI variants do not add CFI flags | 
 | 	bazLibCflags := staticWithCfiLib.Rule("cc").Args["cFlags"] | 
 | 	if strings.Contains(bazLibCflags, "-fsanitize-cfi-cross-dso") { | 
 | 		t.Errorf("non-CFI variant of baz not expected to contain CFI flags ") | 
 | 	} | 
 | } |