diff --git a/android/arch_test.go b/android/arch_test.go index e445ec66f..5021a67af 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -401,7 +401,7 @@ func TestArchMutator(t *testing.T) { { name: "same arch host and host cross", preparer: FixtureModifyConfig(func(config Config) { - modifyTestConfigForMusl(config) + ModifyTestConfigForMusl(config) modifyTestConfigForMuslArm64HostCross(config) }), fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, @@ -705,7 +705,7 @@ func TestArchProperties(t *testing.T) { { name: "linux_musl", goOS: "linux", - preparer: FixtureModifyConfig(modifyTestConfigForMusl), + preparer: FixtureModifyConfig(ModifyTestConfigForMusl), results: []result{ { module: "foo", diff --git a/android/fixture.go b/android/fixture.go index c2b16f66e..dbc3bc5e0 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -16,6 +16,7 @@ package android import ( "fmt" + "runtime" "strings" "testing" ) @@ -379,6 +380,12 @@ func FixtureModifyProductVariables(mutator func(variables FixtureProductVariable }) } +var PrepareForSkipTestOnMac = newSimpleFixturePreparer(func(fixture *fixture) { + if runtime.GOOS != "linux" { + fixture.t.Skip("Test is only supported on linux.") + } +}) + // PrepareForDebug_DO_NOT_SUBMIT puts the fixture into debug which will cause it to output its // state before running the test. // diff --git a/android/test_config.go b/android/test_config.go index 70c319a59..07ca33d56 100644 --- a/android/test_config.go +++ b/android/test_config.go @@ -109,7 +109,8 @@ func modifyTestConfigToSupportArchMutator(testConfig Config) { config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon") } -func modifyTestConfigForMusl(config Config) { +// ModifyTestConfigForMusl takes a Config returned by TestConfig and changes the host targets from glibc to musl. +func ModifyTestConfigForMusl(config Config) { delete(config.Targets, config.BuildOS) config.productVariables.HostMusl = boolPtr(true) determineBuildOS(config.config) diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go index fe592dcb6..71c5a2298 100644 --- a/cc/sanitize_test.go +++ b/cc/sanitize_test.go @@ -28,12 +28,22 @@ import ( 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, } `)) @@ -54,6 +64,19 @@ func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.T } } +// 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) { @@ -68,6 +91,20 @@ func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.T } +// 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) { @@ -85,6 +122,13 @@ func expectInstallDep(t *testing.T, from, to android.TestingModule) { } } +type expectedRuntimeLinkage int + +const ( + RUNTIME_LINKAGE_NONE = expectedRuntimeLinkage(0) + RUNTIME_LINKAGE_SHARED = iota +) + func TestAsan(t *testing.T) { t.Parallel() bp := ` @@ -162,12 +206,14 @@ func TestAsan(t *testing.T) { ` - result := android.GroupFixturePreparers( + preparer := android.GroupFixturePreparers( prepareForCcTest, prepareForAsanTest, - ).RunTestWithBp(t, bp) + ) + buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() - check := func(t *testing.T, result *android.TestResult, variant 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" @@ -198,6 +244,8 @@ func TestAsan(t *testing.T) { libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant) libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant) + libAsanSharedRuntime := result.ModuleForTests("libclang_rt.asan", sharedVariant) + expectSharedLinkDep(t, ctx, binWithAsan, libShared) expectSharedLinkDep(t, ctx, binWithAsan, libAsan) expectSharedLinkDep(t, ctx, libShared, libTransitive) @@ -227,10 +275,28 @@ func TestAsan(t *testing.T) { 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) + } } - t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) }) - t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") }) + 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_SHARED, + android.GroupFixturePreparers(preparer, PrepareForTestWithHostMusl)) + }) } func TestTsan(t *testing.T) { @@ -278,12 +344,14 @@ func TestTsan(t *testing.T) { } ` - result := android.GroupFixturePreparers( + preparer := android.GroupFixturePreparers( prepareForCcTest, prepareForTsanTest, - ).RunTestWithBp(t, bp) + ) + buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() - check := func(t *testing.T, result *android.TestResult, variant 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" @@ -311,8 +379,11 @@ func TestTsan(t *testing.T) { expectSharedLinkDep(t, ctx, libTsan, libTransitive) } - t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) }) - t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") }) + 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) { @@ -369,11 +440,13 @@ func TestMiscUndefined(t *testing.T) { } ` - result := android.GroupFixturePreparers( + preparer := android.GroupFixturePreparers( prepareForCcTest, - ).RunTestWithBp(t, bp) + ) + buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() - check := func(t *testing.T, result *android.TestResult, variant string) { + check := func(t *testing.T, variant string, preparer android.FixturePreparer) { + result := preparer.RunTestWithBp(t, bp) ctx := result.TestContext staticVariant := variant + "_static" @@ -415,8 +488,11 @@ func TestMiscUndefined(t *testing.T) { expectStaticLinkDep(t, ctx, binNoUbsan, libUbsan) } - t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) }) - t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") }) + 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) { @@ -647,11 +723,13 @@ func TestUbsan(t *testing.T) { } ` - result := android.GroupFixturePreparers( + preparer := android.GroupFixturePreparers( prepareForCcTest, - ).RunTestWithBp(t, bp) + ) + buildOS := preparer.RunTestWithBp(t, bp).Config.BuildOSTarget.String() - check := func(t *testing.T, result *android.TestResult, variant string) { + check := func(t *testing.T, variant string, preparer android.FixturePreparer) { + result := preparer.RunTestWithBp(t, bp) staticVariant := variant + "_static" sharedVariant := variant + "_shared" @@ -705,8 +783,11 @@ func TestUbsan(t *testing.T) { "-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base()) } - t.Run("host", func(t *testing.T) { check(t, result, result.Config.BuildOSTarget.String()) }) - t.Run("device", func(t *testing.T) { check(t, result, "android_arm64_armv8-a") }) + 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 diff --git a/cc/testing.go b/cc/testing.go index 992069b5c..d38a57ca8 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -70,6 +70,7 @@ func commonDefaultModules() string { return ` cc_defaults { name: "toolchain_libs_defaults", + host_supported: true, vendor_available: true, product_available: true, recovery_available: true, @@ -134,6 +135,12 @@ func commonDefaultModules() string { srcs: [""], } + cc_prebuilt_library_static { + name: "libclang_rt.ubsan_standalone.static", + defaults: ["toolchain_libs_defaults"], + srcs: [""], + } + cc_prebuilt_library_static { name: "libclang_rt.ubsan_minimal", defaults: ["toolchain_libs_defaults"], @@ -151,6 +158,12 @@ func commonDefaultModules() string { linux_glibc_x86: { srcs: ["libclang_rt.ubsan_minimal.x86.a"], }, + linux_musl_x86_64: { + srcs: ["libclang_rt.ubsan_minimal.x86_64.a"], + }, + linux_musl_x86: { + srcs: ["libclang_rt.ubsan_minimal.x86.a"], + }, }, } @@ -619,6 +632,45 @@ var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers( }), ) +// PrepareForTestWithHostMusl sets the host configuration to musl libc instead of glibc. It also disables the test +// on mac, which doesn't support musl libc, and adds musl modules. +var PrepareForTestWithHostMusl = android.GroupFixturePreparers( + android.FixtureModifyConfig(android.ModifyTestConfigForMusl), + android.PrepareForSkipTestOnMac, + android.FixtureAddTextFile("external/musl/Android.bp", ` + cc_defaults { + name: "libc_musl_crt_defaults", + host_supported: true, + device_supported: false, + } + + cc_object { + name: "libc_musl_crtbegin_so", + defaults: ["libc_musl_crt_defaults"], + } + + cc_object { + name: "libc_musl_crtend_so", + defaults: ["libc_musl_crt_defaults"], + } + + cc_object { + name: "libc_musl_crtbegin_dynamic", + defaults: ["libc_musl_crt_defaults"], + } + + cc_object { + name: "libc_musl_crtbegin_static", + defaults: ["libc_musl_crt_defaults"], + } + + cc_object { + name: "libc_musl_crtend", + defaults: ["libc_musl_crt_defaults"], + } + `), +) + // TestConfig is the legacy way of creating a test Config for testing cc modules. // // See testCc for an explanation as to how to stop using this deprecated method.