Add support for sanitizer property
Add a new feature to cc modules that adds the cflags and libraries necessary to implement AddressSanitizer, ThreadSanitizer, and UndefinedBehaviorSanitizer. Change-Id: Ibe5ffadc7ece56080a2521f2c7c00da9ef712584
This commit is contained in:
@@ -124,6 +124,7 @@ bootstrap_go_package {
|
|||||||
"cc/cc.go",
|
"cc/cc.go",
|
||||||
"cc/clang.go",
|
"cc/clang.go",
|
||||||
"cc/gen.go",
|
"cc/gen.go",
|
||||||
|
"cc/sanitize.go",
|
||||||
"cc/stl.go",
|
"cc/stl.go",
|
||||||
"cc/toolchain.go",
|
"cc/toolchain.go",
|
||||||
"cc/util.go",
|
"cc/util.go",
|
||||||
|
@@ -190,6 +190,10 @@ func (t *toolchainArm64) ToolchainClangCflags() string {
|
|||||||
return t.toolchainClangCflags
|
return t.toolchainClangCflags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (toolchainArm64) AddressSanitizerRuntimeLibrary() string {
|
||||||
|
return "libclang_rt.asan-aarch64-android.so"
|
||||||
|
}
|
||||||
|
|
||||||
func arm64ToolchainFactory(arch common.Arch) Toolchain {
|
func arm64ToolchainFactory(arch common.Arch) Toolchain {
|
||||||
if arch.ArchVariant != "armv8-a" {
|
if arch.ArchVariant != "armv8-a" {
|
||||||
panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
|
panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
|
||||||
|
@@ -337,6 +337,10 @@ func (t *toolchainArm) ClangInstructionSetFlags(isa string) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (toolchainArm) AddressSanitizerRuntimeLibrary() string {
|
||||||
|
return "libclang_rt.asan-arm-android.so"
|
||||||
|
}
|
||||||
|
|
||||||
func armToolchainFactory(arch common.Arch) Toolchain {
|
func armToolchainFactory(arch common.Arch) Toolchain {
|
||||||
var fixCortexA8 string
|
var fixCortexA8 string
|
||||||
toolchainCflags := make([]string, 2, 3)
|
toolchainCflags := make([]string, 2, 3)
|
||||||
|
@@ -133,6 +133,7 @@ type builderFlags struct {
|
|||||||
conlyFlags string
|
conlyFlags string
|
||||||
cppFlags string
|
cppFlags string
|
||||||
ldFlags string
|
ldFlags string
|
||||||
|
libFlags string
|
||||||
yaccFlags string
|
yaccFlags string
|
||||||
nocrt bool
|
nocrt bool
|
||||||
toolchain Toolchain
|
toolchain Toolchain
|
||||||
@@ -190,7 +191,7 @@ func TransformSourceToObj(ctx common.AndroidModuleContext, subdir string, srcFil
|
|||||||
panic("unrecoginzied ccCmd")
|
panic("unrecoginzied ccCmd")
|
||||||
}
|
}
|
||||||
|
|
||||||
ccCmd = "${clangPath}/" + ccCmd
|
ccCmd = "${clangBin}/" + ccCmd
|
||||||
} else {
|
} else {
|
||||||
ccCmd = gccCmd(flags.toolchain, ccCmd)
|
ccCmd = gccCmd(flags.toolchain, ccCmd)
|
||||||
}
|
}
|
||||||
@@ -288,7 +289,7 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
|
|||||||
|
|
||||||
var ldCmd string
|
var ldCmd string
|
||||||
if flags.clang {
|
if flags.clang {
|
||||||
ldCmd = "${clangPath}/clang++"
|
ldCmd = "${clangBin}/clang++"
|
||||||
} else {
|
} else {
|
||||||
ldCmd = gccCmd(flags.toolchain, "g++")
|
ldCmd = gccCmd(flags.toolchain, "g++")
|
||||||
}
|
}
|
||||||
@@ -296,6 +297,10 @@ func TransformObjToDynamicBinary(ctx common.AndroidModuleContext,
|
|||||||
var ldDirs []string
|
var ldDirs []string
|
||||||
var libFlagsList []string
|
var libFlagsList []string
|
||||||
|
|
||||||
|
if len(flags.libFlags) > 0 {
|
||||||
|
libFlagsList = append(libFlagsList, flags.libFlags)
|
||||||
|
}
|
||||||
|
|
||||||
if len(wholeStaticLibs) > 0 {
|
if len(wholeStaticLibs) > 0 {
|
||||||
if ctx.Host() && ctx.Darwin() {
|
if ctx.Host() && ctx.Darwin() {
|
||||||
libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load "))
|
libFlagsList = append(libFlagsList, common.JoinWithPrefix(wholeStaticLibs.Strings(), "-force_load "))
|
||||||
@@ -359,7 +364,7 @@ func TransformObjsToObj(ctx common.AndroidModuleContext, objFiles common.Paths,
|
|||||||
|
|
||||||
var ldCmd string
|
var ldCmd string
|
||||||
if flags.clang {
|
if flags.clang {
|
||||||
ldCmd = "${clangPath}clang++"
|
ldCmd = "${clangBin}clang++"
|
||||||
} else {
|
} else {
|
||||||
ldCmd = gccCmd(flags.toolchain, "g++")
|
ldCmd = gccCmd(flags.toolchain, "g++")
|
||||||
}
|
}
|
||||||
|
94
cc/cc.go
94
cc/cc.go
@@ -59,6 +59,12 @@ func init() {
|
|||||||
common.RegisterBottomUpMutator("link", linkageMutator)
|
common.RegisterBottomUpMutator("link", linkageMutator)
|
||||||
common.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
|
common.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
|
||||||
common.RegisterBottomUpMutator("deps", depsMutator)
|
common.RegisterBottomUpMutator("deps", depsMutator)
|
||||||
|
|
||||||
|
common.RegisterTopDownMutator("asan_deps", sanitizerDepsMutator(asan))
|
||||||
|
common.RegisterBottomUpMutator("asan", sanitizerMutator(asan))
|
||||||
|
|
||||||
|
common.RegisterTopDownMutator("tsan_deps", sanitizerDepsMutator(tsan))
|
||||||
|
common.RegisterBottomUpMutator("tsan", sanitizerMutator(tsan))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -168,7 +174,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
return "clang-2690385", nil
|
return "clang-2690385", nil
|
||||||
})
|
})
|
||||||
pctx.StaticVariable("clangPath", "${clangBase}/${HostPrebuiltTag}/${clangVersion}/bin")
|
pctx.StaticVariable("clangPath", "${clangBase}/${HostPrebuiltTag}/${clangVersion}")
|
||||||
|
pctx.StaticVariable("clangBin", "${clangPath}/bin")
|
||||||
}
|
}
|
||||||
|
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
@@ -208,12 +215,16 @@ type Flags struct {
|
|||||||
CppFlags []string // Flags that apply to C++ source files
|
CppFlags []string // Flags that apply to C++ source files
|
||||||
YaccFlags []string // Flags that apply to Yacc source files
|
YaccFlags []string // Flags that apply to Yacc source files
|
||||||
LdFlags []string // Flags that apply to linker command lines
|
LdFlags []string // Flags that apply to linker command lines
|
||||||
|
libFlags []string // Flags to add libraries early to the link order
|
||||||
|
|
||||||
Nocrt bool
|
Nocrt bool
|
||||||
Toolchain Toolchain
|
Toolchain Toolchain
|
||||||
Clang bool
|
Clang bool
|
||||||
|
|
||||||
RequiredInstructionSet string
|
RequiredInstructionSet string
|
||||||
|
DynamicLinker string
|
||||||
|
|
||||||
|
CFlagsDeps common.Paths // Files depended on by compiler flags
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseCompilerProperties struct {
|
type BaseCompilerProperties struct {
|
||||||
@@ -371,6 +382,8 @@ type LibraryLinkerProperties struct {
|
|||||||
// don't link in crt_begin and crt_end. This flag should only be necessary for
|
// don't link in crt_begin and crt_end. This flag should only be necessary for
|
||||||
// compiling crt or libc.
|
// compiling crt or libc.
|
||||||
Nocrt *bool `android:"arch_variant"`
|
Nocrt *bool `android:"arch_variant"`
|
||||||
|
|
||||||
|
VariantName string `blueprint:"mutated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BinaryLinkerProperties struct {
|
type BinaryLinkerProperties struct {
|
||||||
@@ -426,16 +439,6 @@ type UnusedProperties struct {
|
|||||||
Required []string
|
Required []string
|
||||||
Strip string
|
Strip string
|
||||||
Tags []string
|
Tags []string
|
||||||
Sanitize struct {
|
|
||||||
Never bool `android:"arch_variant"`
|
|
||||||
Address bool `android:"arch_variant"`
|
|
||||||
Thread bool `android:"arch_variant"`
|
|
||||||
Undefined bool `android:"arch_variant"`
|
|
||||||
All_undefined bool `android:"arch_variant"`
|
|
||||||
Misc_undefined []string `android:"arch_variant"`
|
|
||||||
Coverage bool `android:"arch_variant"`
|
|
||||||
Recover []string
|
|
||||||
} `android:"arch_variant"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleContextIntf interface {
|
type ModuleContextIntf interface {
|
||||||
@@ -529,6 +532,9 @@ type Module struct {
|
|||||||
linker linker
|
linker linker
|
||||||
installer installer
|
installer installer
|
||||||
stl *stl
|
stl *stl
|
||||||
|
sanitize *sanitize
|
||||||
|
|
||||||
|
androidMkSharedLibDeps []string
|
||||||
|
|
||||||
outputFile common.OptionalPath
|
outputFile common.OptionalPath
|
||||||
|
|
||||||
@@ -552,6 +558,9 @@ func (c *Module) Init() (blueprint.Module, []interface{}) {
|
|||||||
if c.stl != nil {
|
if c.stl != nil {
|
||||||
props = append(props, c.stl.props()...)
|
props = append(props, c.stl.props()...)
|
||||||
}
|
}
|
||||||
|
if c.sanitize != nil {
|
||||||
|
props = append(props, c.sanitize.props()...)
|
||||||
|
}
|
||||||
for _, feature := range c.features {
|
for _, feature := range c.features {
|
||||||
props = append(props, feature.props()...)
|
props = append(props, feature.props()...)
|
||||||
}
|
}
|
||||||
@@ -632,6 +641,7 @@ func newBaseModule(hod common.HostOrDeviceSupported, multilib common.Multilib) *
|
|||||||
func newModule(hod common.HostOrDeviceSupported, multilib common.Multilib) *Module {
|
func newModule(hod common.HostOrDeviceSupported, multilib common.Multilib) *Module {
|
||||||
module := newBaseModule(hod, multilib)
|
module := newBaseModule(hod, multilib)
|
||||||
module.stl = &stl{}
|
module.stl = &stl{}
|
||||||
|
module.sanitize = &sanitize{}
|
||||||
return module
|
return module
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +658,6 @@ func (c *Module) GenerateAndroidBuildActions(actx common.AndroidModuleContext) {
|
|||||||
Toolchain: c.toolchain(ctx),
|
Toolchain: c.toolchain(ctx),
|
||||||
Clang: c.clang(ctx),
|
Clang: c.clang(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.compiler != nil {
|
if c.compiler != nil {
|
||||||
flags = c.compiler.flags(ctx, flags)
|
flags = c.compiler.flags(ctx, flags)
|
||||||
}
|
}
|
||||||
@@ -658,6 +667,9 @@ func (c *Module) GenerateAndroidBuildActions(actx common.AndroidModuleContext) {
|
|||||||
if c.stl != nil {
|
if c.stl != nil {
|
||||||
flags = c.stl.flags(ctx, flags)
|
flags = c.stl.flags(ctx, flags)
|
||||||
}
|
}
|
||||||
|
if c.sanitize != nil {
|
||||||
|
flags = c.sanitize.flags(ctx, flags)
|
||||||
|
}
|
||||||
for _, feature := range c.features {
|
for _, feature := range c.features {
|
||||||
flags = feature.flags(ctx, flags)
|
flags = feature.flags(ctx, flags)
|
||||||
}
|
}
|
||||||
@@ -734,6 +746,9 @@ func (c *Module) begin(ctx BaseModuleContext) {
|
|||||||
if c.stl != nil {
|
if c.stl != nil {
|
||||||
c.stl.begin(ctx)
|
c.stl.begin(ctx)
|
||||||
}
|
}
|
||||||
|
if c.sanitize != nil {
|
||||||
|
c.sanitize.begin(ctx)
|
||||||
|
}
|
||||||
for _, feature := range c.features {
|
for _, feature := range c.features {
|
||||||
feature.begin(ctx)
|
feature.begin(ctx)
|
||||||
}
|
}
|
||||||
@@ -751,6 +766,9 @@ func (c *Module) deps(ctx BaseModuleContext) Deps {
|
|||||||
if c.stl != nil {
|
if c.stl != nil {
|
||||||
deps = c.stl.deps(ctx, deps)
|
deps = c.stl.deps(ctx, deps)
|
||||||
}
|
}
|
||||||
|
if c.sanitize != nil {
|
||||||
|
deps = c.sanitize.deps(ctx, deps)
|
||||||
|
}
|
||||||
for _, feature := range c.features {
|
for _, feature := range c.features {
|
||||||
deps = feature.deps(ctx, deps)
|
deps = feature.deps(ctx, deps)
|
||||||
}
|
}
|
||||||
@@ -960,6 +978,20 @@ func (c *Module) InstallInData() bool {
|
|||||||
return c.installer.inData()
|
return c.installer.inData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type appendVariantName interface {
|
||||||
|
appendVariantName(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Module) appendVariantName(name string) {
|
||||||
|
if c.linker == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l, ok := c.linker.(appendVariantName); ok {
|
||||||
|
l.appendVariantName(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compiler
|
// Compiler
|
||||||
|
|
||||||
type baseCompiler struct {
|
type baseCompiler struct {
|
||||||
@@ -1152,6 +1184,7 @@ func (compiler *baseCompiler) compileObjs(ctx common.AndroidModuleContext, flags
|
|||||||
srcPaths, gendeps := genSources(ctx, inputFiles, buildFlags)
|
srcPaths, gendeps := genSources(ctx, inputFiles, buildFlags)
|
||||||
|
|
||||||
deps = append(deps, gendeps...)
|
deps = append(deps, gendeps...)
|
||||||
|
deps = append(deps, flags.CFlagsDeps...)
|
||||||
|
|
||||||
return TransformSourceToObj(ctx, subdir, srcPaths, buildFlags, deps)
|
return TransformSourceToObj(ctx, subdir, srcPaths, buildFlags, deps)
|
||||||
}
|
}
|
||||||
@@ -1269,6 +1302,10 @@ func (linker *baseLinker) setStatic(static bool) {
|
|||||||
linker.dynamicProperties.VariantIsStatic = static
|
linker.dynamicProperties.VariantIsStatic = static
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (linker *baseLinker) isDependencyRoot() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
type baseLinkerInterface interface {
|
type baseLinkerInterface interface {
|
||||||
// Returns true if the build options for the module have selected a static or shared build
|
// Returns true if the build options for the module have selected a static or shared build
|
||||||
buildStatic() bool
|
buildStatic() bool
|
||||||
@@ -1282,6 +1319,10 @@ type baseLinkerInterface interface {
|
|||||||
|
|
||||||
// Returns whether a module is a static binary
|
// Returns whether a module is a static binary
|
||||||
staticBinary() bool
|
staticBinary() bool
|
||||||
|
|
||||||
|
// Returns true for dependency roots (binaries)
|
||||||
|
// TODO(ccross): also handle dlopenable libraries
|
||||||
|
isDependencyRoot() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type baseInstaller struct {
|
type baseInstaller struct {
|
||||||
@@ -1417,6 +1458,7 @@ type libraryLinker struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ linker = (*libraryLinker)(nil)
|
var _ linker = (*libraryLinker)(nil)
|
||||||
|
var _ appendVariantName = (*libraryLinker)(nil)
|
||||||
|
|
||||||
func (library *libraryLinker) props() []interface{} {
|
func (library *libraryLinker) props() []interface{} {
|
||||||
props := library.baseLinker.props()
|
props := library.baseLinker.props()
|
||||||
@@ -1493,7 +1535,8 @@ func (library *libraryLinker) linkStatic(ctx ModuleContext,
|
|||||||
objFiles = append(objFiles, deps.WholeStaticLibObjFiles...)
|
objFiles = append(objFiles, deps.WholeStaticLibObjFiles...)
|
||||||
library.objFiles = objFiles
|
library.objFiles = objFiles
|
||||||
|
|
||||||
outputFile := common.PathForModuleOut(ctx, ctx.ModuleName()+staticLibraryExtension)
|
outputFile := common.PathForModuleOut(ctx,
|
||||||
|
ctx.ModuleName()+library.Properties.VariantName+staticLibraryExtension)
|
||||||
|
|
||||||
if ctx.Darwin() {
|
if ctx.Darwin() {
|
||||||
TransformDarwinObjToStaticLib(ctx, objFiles, flagsToBuilderFlags(flags), outputFile)
|
TransformDarwinObjToStaticLib(ctx, objFiles, flagsToBuilderFlags(flags), outputFile)
|
||||||
@@ -1511,7 +1554,8 @@ func (library *libraryLinker) linkStatic(ctx ModuleContext,
|
|||||||
func (library *libraryLinker) linkShared(ctx ModuleContext,
|
func (library *libraryLinker) linkShared(ctx ModuleContext,
|
||||||
flags Flags, deps PathDeps, objFiles common.Paths) common.Path {
|
flags Flags, deps PathDeps, objFiles common.Paths) common.Path {
|
||||||
|
|
||||||
outputFile := common.PathForModuleOut(ctx, ctx.ModuleName()+flags.Toolchain.ShlibSuffix())
|
outputFile := common.PathForModuleOut(ctx,
|
||||||
|
ctx.ModuleName()+library.Properties.VariantName+flags.Toolchain.ShlibSuffix())
|
||||||
|
|
||||||
var linkerDeps common.Paths
|
var linkerDeps common.Paths
|
||||||
|
|
||||||
@@ -1595,6 +1639,10 @@ func (library *libraryLinker) installable() bool {
|
|||||||
return !library.static()
|
return !library.static()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (library *libraryLinker) appendVariantName(variant string) {
|
||||||
|
library.Properties.VariantName += variant
|
||||||
|
}
|
||||||
|
|
||||||
type libraryInstaller struct {
|
type libraryInstaller struct {
|
||||||
baseInstaller
|
baseInstaller
|
||||||
|
|
||||||
@@ -1771,6 +1819,10 @@ func (*binaryLinker) installable() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (binary *binaryLinker) isDependencyRoot() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func NewBinary(hod common.HostOrDeviceSupported) *Module {
|
func NewBinary(hod common.HostOrDeviceSupported) *Module {
|
||||||
module := newModule(hod, common.MultilibFirst)
|
module := newModule(hod, common.MultilibFirst)
|
||||||
module.compiler = &baseCompiler{}
|
module.compiler = &baseCompiler{}
|
||||||
@@ -1829,16 +1881,17 @@ func (binary *binaryLinker) flags(ctx ModuleContext, flags Flags) Flags {
|
|||||||
)
|
)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
linker := "/system/bin/linker"
|
if flags.DynamicLinker == "" {
|
||||||
if flags.Toolchain.Is64Bit() {
|
flags.DynamicLinker = "/system/bin/linker"
|
||||||
linker += "64"
|
if flags.Toolchain.Is64Bit() {
|
||||||
|
flags.DynamicLinker += "64"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flags.LdFlags = append(flags.LdFlags,
|
flags.LdFlags = append(flags.LdFlags,
|
||||||
"-pie",
|
"-pie",
|
||||||
"-nostdlib",
|
"-nostdlib",
|
||||||
"-Bdynamic",
|
"-Bdynamic",
|
||||||
fmt.Sprintf("-Wl,-dynamic-linker,%s", linker),
|
|
||||||
"-Wl,--gc-sections",
|
"-Wl,--gc-sections",
|
||||||
"-Wl,-z,nocopyreloc",
|
"-Wl,-z,nocopyreloc",
|
||||||
)
|
)
|
||||||
@@ -1871,6 +1924,10 @@ func (binary *binaryLinker) link(ctx ModuleContext,
|
|||||||
sharedLibs := deps.SharedLibs
|
sharedLibs := deps.SharedLibs
|
||||||
sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
|
sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
|
||||||
|
|
||||||
|
if flags.DynamicLinker != "" {
|
||||||
|
flags.LdFlags = append(flags.LdFlags, " -Wl,-dynamic-linker,"+flags.DynamicLinker)
|
||||||
|
}
|
||||||
|
|
||||||
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs,
|
TransformObjToDynamicBinary(ctx, objFiles, sharedLibs, deps.StaticLibs,
|
||||||
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
|
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
|
||||||
flagsToBuilderFlags(flags), outputFile)
|
flagsToBuilderFlags(flags), outputFile)
|
||||||
@@ -2101,6 +2158,7 @@ func defaultsFactory() (blueprint.Module, []interface{}) {
|
|||||||
&TestLinkerProperties{},
|
&TestLinkerProperties{},
|
||||||
&UnusedProperties{},
|
&UnusedProperties{},
|
||||||
&StlProperties{},
|
&StlProperties{},
|
||||||
|
&SanitizeProperties{},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, propertyStructs = common.InitAndroidArchModule(module, common.HostAndDeviceDefault,
|
_, propertyStructs = common.InitAndroidArchModule(module, common.HostAndDeviceDefault,
|
||||||
|
329
cc/sanitize.go
Normal file
329
cc/sanitize.go
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
// Copyright 2016 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"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/blueprint"
|
||||||
|
|
||||||
|
"android/soong/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sanitizerType int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pctx.StaticVariable("clangAsanLibDir", "${clangPath}/lib64/clang/3.8/lib/linux")
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
asan sanitizerType = iota + 1
|
||||||
|
tsan
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t sanitizerType) String() string {
|
||||||
|
switch t {
|
||||||
|
case asan:
|
||||||
|
return "asan"
|
||||||
|
case tsan:
|
||||||
|
return "tsan"
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unknown sanitizerType %d", t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type SanitizeProperties struct {
|
||||||
|
// enable AddressSanitizer, ThreadSanitizer, or UndefinedBehaviorSanitizer
|
||||||
|
Sanitize struct {
|
||||||
|
Never bool `android:"arch_variant"`
|
||||||
|
|
||||||
|
// main sanitizers
|
||||||
|
Address bool `android:"arch_variant"`
|
||||||
|
Thread bool `android:"arch_variant"`
|
||||||
|
|
||||||
|
// local sanitizers
|
||||||
|
Undefined bool `android:"arch_variant"`
|
||||||
|
All_undefined bool `android:"arch_variant"`
|
||||||
|
Misc_undefined []string `android:"arch_variant"`
|
||||||
|
Coverage bool `android:"arch_variant"`
|
||||||
|
|
||||||
|
// value to pass to -fsantitize-recover=
|
||||||
|
Recover []string
|
||||||
|
|
||||||
|
// value to pass to -fsanitize-blacklist
|
||||||
|
Blacklist *string
|
||||||
|
} `android:"arch_variant"`
|
||||||
|
|
||||||
|
SanitizerEnabled bool `blueprint:"mutated"`
|
||||||
|
SanitizeDep bool `blueprint:"mutated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type sanitize struct {
|
||||||
|
Properties SanitizeProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) props() []interface{} {
|
||||||
|
return []interface{}{&sanitize.Properties}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) begin(ctx BaseModuleContext) {
|
||||||
|
// Don't apply sanitizers to NDK code.
|
||||||
|
if ctx.sdk() {
|
||||||
|
sanitize.Properties.Sanitize.Never = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Never always wins.
|
||||||
|
if sanitize.Properties.Sanitize.Never {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.ContainsProperty("sanitize") {
|
||||||
|
sanitize.Properties.SanitizerEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var globalSanitizers []string
|
||||||
|
if ctx.clang() {
|
||||||
|
if ctx.Host() {
|
||||||
|
globalSanitizers = ctx.AConfig().SanitizeHost()
|
||||||
|
} else {
|
||||||
|
globalSanitizers = ctx.AConfig().SanitizeDevice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The sanitizer specified by the environment wins over the module.
|
||||||
|
if len(globalSanitizers) > 0 {
|
||||||
|
// wipe the enabled sanitizers
|
||||||
|
sanitize.Properties = SanitizeProperties{}
|
||||||
|
var found bool
|
||||||
|
if found, globalSanitizers = removeFromList("undefined", globalSanitizers); found {
|
||||||
|
sanitize.Properties.Sanitize.All_undefined = true
|
||||||
|
} else if found, globalSanitizers = removeFromList("default-ub", globalSanitizers); found {
|
||||||
|
sanitize.Properties.Sanitize.Undefined = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if found, globalSanitizers = removeFromList("address", globalSanitizers); found {
|
||||||
|
sanitize.Properties.Sanitize.Address = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if found, globalSanitizers = removeFromList("thread", globalSanitizers); found {
|
||||||
|
sanitize.Properties.Sanitize.Thread = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if found, globalSanitizers = removeFromList("coverage", globalSanitizers); found {
|
||||||
|
sanitize.Properties.Sanitize.Coverage = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(globalSanitizers) > 0 {
|
||||||
|
ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
|
||||||
|
}
|
||||||
|
sanitize.Properties.SanitizerEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.toolchain().Is64Bit() && sanitize.Properties.Sanitize.Thread {
|
||||||
|
// TSAN is not supported on 32-bit architectures
|
||||||
|
sanitize.Properties.Sanitize.Thread = false
|
||||||
|
// TODO(ccross): error for compile_multilib = "32"?
|
||||||
|
}
|
||||||
|
|
||||||
|
if sanitize.Properties.Sanitize.Coverage {
|
||||||
|
if !sanitize.Properties.Sanitize.Address {
|
||||||
|
ctx.ModuleErrorf(`Use of "coverage" also requires "address"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) deps(ctx BaseModuleContext, deps Deps) Deps {
|
||||||
|
if !sanitize.Properties.SanitizerEnabled { // || c.static() {
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Device() {
|
||||||
|
deps.SharedLibs = append(deps.SharedLibs, "libdl")
|
||||||
|
if sanitize.Properties.Sanitize.Address {
|
||||||
|
deps.StaticLibs = append(deps.StaticLibs, "libasan")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags) Flags {
|
||||||
|
if !sanitize.Properties.SanitizerEnabled {
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ctx.clang() {
|
||||||
|
ctx.ModuleErrorf("Use of sanitizers requires clang")
|
||||||
|
}
|
||||||
|
|
||||||
|
var sanitizers []string
|
||||||
|
|
||||||
|
if sanitize.Properties.Sanitize.All_undefined {
|
||||||
|
sanitizers = append(sanitizers, "undefined")
|
||||||
|
if ctx.Device() {
|
||||||
|
ctx.ModuleErrorf("ubsan is not yet supported on the device")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if sanitize.Properties.Sanitize.Undefined {
|
||||||
|
sanitizers = append(sanitizers,
|
||||||
|
"bool",
|
||||||
|
"integer-divide-by-zero",
|
||||||
|
"return",
|
||||||
|
"returns-nonnull-attribute",
|
||||||
|
"shift-exponent",
|
||||||
|
"unreachable",
|
||||||
|
"vla-bound",
|
||||||
|
// TODO(danalbert): The following checks currently have compiler performance issues.
|
||||||
|
//"alignment",
|
||||||
|
//"bounds",
|
||||||
|
//"enum",
|
||||||
|
//"float-cast-overflow",
|
||||||
|
//"float-divide-by-zero",
|
||||||
|
//"nonnull-attribute",
|
||||||
|
//"null",
|
||||||
|
//"shift-base",
|
||||||
|
//"signed-integer-overflow",
|
||||||
|
// TODO(danalbert): Fix UB in libc++'s __tree so we can turn this on.
|
||||||
|
// https://llvm.org/PR19302
|
||||||
|
// http://reviews.llvm.org/D6974
|
||||||
|
// "object-size",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sanitizers = append(sanitizers, sanitize.Properties.Sanitize.Misc_undefined...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sanitize.Properties.Sanitize.Address {
|
||||||
|
if ctx.Arch().ArchType == common.Arm {
|
||||||
|
// Frame pointer based unwinder in ASan requires ARM frame setup.
|
||||||
|
// TODO: put in flags?
|
||||||
|
flags.RequiredInstructionSet = "arm"
|
||||||
|
}
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fno-omit-frame-pointer")
|
||||||
|
flags.LdFlags = append(flags.LdFlags, "-Wl,-u,__asan_preinit")
|
||||||
|
|
||||||
|
// ASan runtime library must be the first in the link order.
|
||||||
|
runtimeLibrary := ctx.toolchain().AddressSanitizerRuntimeLibrary()
|
||||||
|
if runtimeLibrary != "" {
|
||||||
|
flags.libFlags = append([]string{"${clangAsanLibDir}/" + runtimeLibrary}, flags.libFlags...)
|
||||||
|
}
|
||||||
|
if ctx.Host() {
|
||||||
|
// -nodefaultlibs (provided with libc++) prevents the driver from linking
|
||||||
|
// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
|
||||||
|
flags.LdFlags = append(flags.LdFlags, "-lm", "-lpthread")
|
||||||
|
flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
|
||||||
|
} else {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
|
||||||
|
flags.DynamicLinker = "/system/bin/linker_asan"
|
||||||
|
if flags.Toolchain.Is64Bit() {
|
||||||
|
flags.DynamicLinker += "64"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sanitizers = append(sanitizers, "address")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sanitize.Properties.Sanitize.Coverage {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fsanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp")
|
||||||
|
}
|
||||||
|
|
||||||
|
if sanitize.Properties.Sanitize.Recover != nil {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fsanitize-recover="+
|
||||||
|
strings.Join(sanitize.Properties.Sanitize.Recover, ","))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sanitizers) > 0 {
|
||||||
|
sanitizeArg := "-fsanitize=" + strings.Join(sanitizers, ",")
|
||||||
|
flags.CFlags = append(flags.CFlags, sanitizeArg)
|
||||||
|
if ctx.Host() {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fno-sanitize-recover=all")
|
||||||
|
flags.LdFlags = append(flags.LdFlags, sanitizeArg)
|
||||||
|
flags.LdFlags = append(flags.LdFlags, "-lrt", "-ldl")
|
||||||
|
} else {
|
||||||
|
if !sanitize.Properties.Sanitize.Address {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fsanitize-trap=all", "-ftrap-function=abort")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blacklist := common.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
|
||||||
|
if blacklist.Valid() {
|
||||||
|
flags.CFlags = append(flags.CFlags, "-fsanitize-blacklist="+blacklist.String())
|
||||||
|
flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) Sanitizer(t sanitizerType) bool {
|
||||||
|
if sanitize == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t {
|
||||||
|
case asan:
|
||||||
|
return sanitize.Properties.Sanitize.Address
|
||||||
|
case tsan:
|
||||||
|
return sanitize.Properties.Sanitize.Thread
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unknown sanitizerType %d", t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sanitize *sanitize) SetSanitizer(t sanitizerType, b bool) {
|
||||||
|
switch t {
|
||||||
|
case asan:
|
||||||
|
sanitize.Properties.Sanitize.Address = b
|
||||||
|
case tsan:
|
||||||
|
sanitize.Properties.Sanitize.Thread = b
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unknown sanitizerType %d", t))
|
||||||
|
}
|
||||||
|
if b {
|
||||||
|
sanitize.Properties.SanitizerEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate asan requirements down from binaries
|
||||||
|
func sanitizerDepsMutator(t sanitizerType) func(common.AndroidTopDownMutatorContext) {
|
||||||
|
return func(mctx common.AndroidTopDownMutatorContext) {
|
||||||
|
if c, ok := mctx.Module().(*Module); ok && c.sanitize.Sanitizer(t) {
|
||||||
|
mctx.VisitDepsDepthFirst(func(module blueprint.Module) {
|
||||||
|
if d, ok := mctx.Module().(*Module); ok && c.sanitize != nil &&
|
||||||
|
!c.sanitize.Properties.Sanitize.Never {
|
||||||
|
d.sanitize.Properties.SanitizeDep = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create asan variants for modules that need them
|
||||||
|
func sanitizerMutator(t sanitizerType) func(common.AndroidBottomUpMutatorContext) {
|
||||||
|
return func(mctx common.AndroidBottomUpMutatorContext) {
|
||||||
|
if c, ok := mctx.Module().(*Module); ok && c.sanitize != nil {
|
||||||
|
if d, ok := c.linker.(baseLinkerInterface); ok && d.isDependencyRoot() && c.sanitize.Sanitizer(t) {
|
||||||
|
mctx.CreateVariations(t.String())
|
||||||
|
} else if c.sanitize.Properties.SanitizeDep {
|
||||||
|
modules := mctx.CreateVariations("", t.String())
|
||||||
|
modules[0].(*Module).sanitize.SetSanitizer(t, false)
|
||||||
|
modules[1].(*Module).sanitize.SetSanitizer(t, true)
|
||||||
|
modules[1].(*Module).appendVariantName("_" + t.String())
|
||||||
|
modules[0].(*Module).sanitize.Properties.SanitizeDep = false
|
||||||
|
modules[1].(*Module).sanitize.Properties.SanitizeDep = false
|
||||||
|
}
|
||||||
|
c.sanitize.Properties.SanitizeDep = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -74,6 +74,8 @@ type Toolchain interface {
|
|||||||
|
|
||||||
SystemCppCppflags() string
|
SystemCppCppflags() string
|
||||||
SystemCppLdflags() string
|
SystemCppLdflags() string
|
||||||
|
|
||||||
|
AddressSanitizerRuntimeLibrary() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type toolchainBase struct {
|
type toolchainBase struct {
|
||||||
@@ -133,6 +135,10 @@ func (toolchainBase) SystemCppLdflags() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (toolchainBase) AddressSanitizerRuntimeLibrary() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type toolchain64Bit struct {
|
type toolchain64Bit struct {
|
||||||
toolchainBase
|
toolchainBase
|
||||||
}
|
}
|
||||||
|
22
cc/util.go
22
cc/util.go
@@ -40,14 +40,18 @@ func libNamesToFlags(names []string) string {
|
|||||||
return common.JoinWithPrefix(names, "-l")
|
return common.JoinWithPrefix(names, "-l")
|
||||||
}
|
}
|
||||||
|
|
||||||
func inList(s string, list []string) bool {
|
func indexList(s string, list []string) int {
|
||||||
for _, l := range list {
|
for i, l := range list {
|
||||||
if l == s {
|
if l == s {
|
||||||
return true
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func inList(s string, list []string) bool {
|
||||||
|
return indexList(s, list) != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterList(list []string, filter []string) (remainder []string, filtered []string) {
|
func filterList(list []string, filter []string) (remainder []string, filtered []string) {
|
||||||
@@ -62,6 +66,15 @@ func filterList(list []string, filter []string) (remainder []string, filtered []
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeFromList(s string, list []string) (bool, []string) {
|
||||||
|
i := indexList(s, list)
|
||||||
|
if i != -1 {
|
||||||
|
return true, append(list[:i], list[i+1:]...)
|
||||||
|
} else {
|
||||||
|
return false, list
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var libNameRegexp = regexp.MustCompile(`^lib(.*)$`)
|
var libNameRegexp = regexp.MustCompile(`^lib(.*)$`)
|
||||||
|
|
||||||
func moduleToLibName(module string) (string, error) {
|
func moduleToLibName(module string) (string, error) {
|
||||||
@@ -81,6 +94,7 @@ func flagsToBuilderFlags(in Flags) builderFlags {
|
|||||||
cppFlags: strings.Join(in.CppFlags, " "),
|
cppFlags: strings.Join(in.CppFlags, " "),
|
||||||
yaccFlags: strings.Join(in.YaccFlags, " "),
|
yaccFlags: strings.Join(in.YaccFlags, " "),
|
||||||
ldFlags: strings.Join(in.LdFlags, " "),
|
ldFlags: strings.Join(in.LdFlags, " "),
|
||||||
|
libFlags: strings.Join(in.libFlags, " "),
|
||||||
nocrt: in.Nocrt,
|
nocrt: in.Nocrt,
|
||||||
toolchain: in.Toolchain,
|
toolchain: in.Toolchain,
|
||||||
clang: in.Clang,
|
clang: in.Clang,
|
||||||
|
@@ -236,6 +236,10 @@ func (t *toolchainX86) ClangLdflags() string {
|
|||||||
return "${x86Ldflags}"
|
return "${x86Ldflags}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (toolchainX86) AddressSanitizerRuntimeLibrary() string {
|
||||||
|
return "libclang_rt.asan-i686-android.so"
|
||||||
|
}
|
||||||
|
|
||||||
func x86ToolchainFactory(arch common.Arch) Toolchain {
|
func x86ToolchainFactory(arch common.Arch) Toolchain {
|
||||||
toolchainCflags := []string{
|
toolchainCflags := []string{
|
||||||
"${x86ToolchainCflags}",
|
"${x86ToolchainCflags}",
|
||||||
|
@@ -307,3 +307,17 @@ func (c *config) AllowMissingDependencies() bool {
|
|||||||
func (c *config) SkipDeviceInstall() bool {
|
func (c *config) SkipDeviceInstall() bool {
|
||||||
return c.EmbeddedInMake() || Bool(c.Mega_device)
|
return c.EmbeddedInMake() || Bool(c.Mega_device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *config) SanitizeHost() []string {
|
||||||
|
if c.ProductVariables.SanitizeHost == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *c.ProductVariables.SanitizeHost
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *config) SanitizeDevice() []string {
|
||||||
|
if c.ProductVariables.SanitizeDevice == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *c.ProductVariables.SanitizeDevice
|
||||||
|
}
|
||||||
|
@@ -77,6 +77,9 @@ type productVariables struct {
|
|||||||
Unbundled_build *bool `json:",omitempty"`
|
Unbundled_build *bool `json:",omitempty"`
|
||||||
Brillo *bool `json:",omitempty"`
|
Brillo *bool `json:",omitempty"`
|
||||||
Malloc_not_svelte *bool `json:",omitempty"`
|
Malloc_not_svelte *bool `json:",omitempty"`
|
||||||
|
|
||||||
|
SanitizeHost *[]string `json:",omitempty"`
|
||||||
|
SanitizeDevice *[]string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func boolPtr(v bool) *bool {
|
func boolPtr(v bool) *bool {
|
||||||
|
Reference in New Issue
Block a user