// 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 ( "testing" "android/soong/android" ) var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(` cc_library_shared { name: "libclang_rt.asan-aarch64-android", } cc_library_shared { name: "libclang_rt.asan-arm-android", } `)) func TestAsan(t *testing.T) { bp := ` cc_binary { name: "bin_with_asan", host_supported: true, shared_libs: [ "libshared", "libasan", ], static_libs: [ "libstatic", "libnoasan", ], sanitize: { address: true, } } cc_binary { name: "bin_no_asan", host_supported: true, shared_libs: [ "libshared", "libasan", ], static_libs: [ "libstatic", "libnoasan", ], } 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, } } ` result := android.GroupFixturePreparers( prepareForCcTest, prepareForAsanTest, ).RunTestWithBp(t, bp) check := func(t *testing.T, result *android.TestResult, variant string) { 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) // expectSharedLinkDep verifies that the from module links against the to module as a // shared library. expectSharedLinkDep := func(from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") toLink := to.Description("strip") if g, w := fromLink.OrderOnly.Strings(), toLink.Output.String(); !android.InList(w, g) { t.Errorf("%s should 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. expectStaticLinkDep := func(from, to android.TestingModule) { t.Helper() fromLink := from.Description("link") toLink := to.Description("static link") if g, w := fromLink.Implicits.Strings(), toLink.Output.String(); !android.InList(w, g) { t.Errorf("%s should 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. expectInstallDep := func(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) } } expectSharedLinkDep(binWithAsan, libShared) expectSharedLinkDep(binWithAsan, libAsan) expectSharedLinkDep(libShared, libTransitive) expectSharedLinkDep(libAsan, libTransitive) expectStaticLinkDep(binWithAsan, libStaticAsanVariant) expectStaticLinkDep(binWithAsan, libNoAsan) expectInstallDep(binWithAsan, libShared) expectInstallDep(binWithAsan, libAsan) expectInstallDep(binWithAsan, libTransitive) expectInstallDep(libShared, libTransitive) expectInstallDep(libAsan, libTransitive) expectSharedLinkDep(binNoAsan, libShared) expectSharedLinkDep(binNoAsan, libAsan) expectSharedLinkDep(libShared, libTransitive) expectSharedLinkDep(libAsan, libTransitive) expectStaticLinkDep(binNoAsan, libStaticNoAsanVariant) expectStaticLinkDep(binNoAsan, libNoAsan) expectInstallDep(binNoAsan, libShared) expectInstallDep(binNoAsan, libAsan) expectInstallDep(binNoAsan, libTransitive) expectInstallDep(libShared, libTransitive) expectInstallDep(libAsan, 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") }) }