platform_build_soong/cc/sanitize_test.go
Colin Cross 0df8153267 Fix adding manual ubsan runtime to static glibc binaries
Sanitized glibc binaries get their runtime added by clang, not by
Soong, but unsanitized glibc binaries with sanitized dependencies
need their runtime added manually by Soong.  Fix adding a static
runtime dependency to static glibc binaries.

Fixes: 297250415
Test: TestUbsan
Change-Id: I4913326604f9efebd8ecd4aad2f109fad8b6a80c
2023-08-23 22:39:58 -07:00

1275 lines
47 KiB
Go

// 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 ")
}
}