Merge "Migrate sanitizers to transition mutators."
This commit is contained in:
@@ -93,6 +93,7 @@ type RegisterMutatorsContext interface {
|
|||||||
TopDown(name string, m TopDownMutator) MutatorHandle
|
TopDown(name string, m TopDownMutator) MutatorHandle
|
||||||
BottomUp(name string, m BottomUpMutator) MutatorHandle
|
BottomUp(name string, m BottomUpMutator) MutatorHandle
|
||||||
BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
|
BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
|
||||||
|
Transition(name string, m TransitionMutator)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegisterMutatorFunc func(RegisterMutatorsContext)
|
type RegisterMutatorFunc func(RegisterMutatorsContext)
|
||||||
@@ -421,6 +422,124 @@ func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.Bot
|
|||||||
return mutator
|
return mutator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IncomingTransitionContext interface {
|
||||||
|
// Module returns the target of the dependency edge for which the transition
|
||||||
|
// is being computed
|
||||||
|
Module() Module
|
||||||
|
|
||||||
|
// Config returns the configuration for the build.
|
||||||
|
Config() Config
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutgoingTransitionContext interface {
|
||||||
|
// Module returns the target of the dependency edge for which the transition
|
||||||
|
// is being computed
|
||||||
|
Module() Module
|
||||||
|
|
||||||
|
// DepTag() Returns the dependency tag through which this dependency is
|
||||||
|
// reached
|
||||||
|
DepTag() blueprint.DependencyTag
|
||||||
|
}
|
||||||
|
type TransitionMutator interface {
|
||||||
|
// Split returns the set of variations that should be created for a module no
|
||||||
|
// matter who depends on it. Used when Make depends on a particular variation
|
||||||
|
// or when the module knows its variations just based on information given to
|
||||||
|
// it in the Blueprint file. This method should not mutate the module it is
|
||||||
|
// called on.
|
||||||
|
Split(ctx BaseModuleContext) []string
|
||||||
|
|
||||||
|
// OutCalled on a module to determine which variation it wants from its direct
|
||||||
|
// dependencies. The dependency itself can override this decision. This method
|
||||||
|
// should not mutate the module itself.
|
||||||
|
OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
|
||||||
|
|
||||||
|
// Called on a module to determine which variation it should be in based on
|
||||||
|
// the variation modules that depend on it want. This gives the module a final
|
||||||
|
// say about its own variations. This method should not mutate the module
|
||||||
|
// itself.
|
||||||
|
IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
|
||||||
|
|
||||||
|
// Called after a module was split into multiple variations on each variation.
|
||||||
|
// It should not split the module any further but adding new dependencies is
|
||||||
|
// fine. Unlike all the other methods on TransitionMutator, this method is
|
||||||
|
// allowed to mutate the module.
|
||||||
|
Mutate(ctx BottomUpMutatorContext, variation string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type androidTransitionMutator struct {
|
||||||
|
finalPhase bool
|
||||||
|
bazelConversionMode bool
|
||||||
|
mutator TransitionMutator
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
|
||||||
|
if m, ok := ctx.Module().(Module); ok {
|
||||||
|
moduleContext := m.base().baseModuleContextFactory(ctx)
|
||||||
|
moduleContext.bazelConversionMode = a.bazelConversionMode
|
||||||
|
return a.mutator.Split(&moduleContext)
|
||||||
|
} else {
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type outgoingTransitionContextImpl struct {
|
||||||
|
bp blueprint.OutgoingTransitionContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *outgoingTransitionContextImpl) Module() Module {
|
||||||
|
return c.bp.Module().(Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag {
|
||||||
|
return c.bp.DepTag()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *androidTransitionMutator) OutgoingTransition(ctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
|
||||||
|
if _, ok := ctx.Module().(Module); ok {
|
||||||
|
return a.mutator.OutgoingTransition(&outgoingTransitionContextImpl{bp: ctx}, sourceVariation)
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type incomingTransitionContextImpl struct {
|
||||||
|
bp blueprint.IncomingTransitionContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *incomingTransitionContextImpl) Module() Module {
|
||||||
|
return c.bp.Module().(Module)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *incomingTransitionContextImpl) Config() Config {
|
||||||
|
return c.bp.Config().(Config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *androidTransitionMutator) IncomingTransition(ctx blueprint.IncomingTransitionContext, incomingVariation string) string {
|
||||||
|
if _, ok := ctx.Module().(Module); ok {
|
||||||
|
return a.mutator.IncomingTransition(&incomingTransitionContextImpl{bp: ctx}, incomingVariation)
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
|
||||||
|
if am, ok := ctx.Module().(Module); ok {
|
||||||
|
a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase, a.bazelConversionMode), variation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
|
||||||
|
atm := &androidTransitionMutator{
|
||||||
|
finalPhase: x.finalPhase,
|
||||||
|
bazelConversionMode: x.bazelConversionMode,
|
||||||
|
mutator: m,
|
||||||
|
}
|
||||||
|
mutator := &mutator{
|
||||||
|
name: name,
|
||||||
|
transitionMutator: atm}
|
||||||
|
x.mutators = append(x.mutators, mutator)
|
||||||
|
}
|
||||||
|
|
||||||
func (x *registerMutatorsContext) mutatorName(name string) string {
|
func (x *registerMutatorsContext) mutatorName(name string) string {
|
||||||
if x.bazelConversionMode {
|
if x.bazelConversionMode {
|
||||||
return name + "_bp2build"
|
return name + "_bp2build"
|
||||||
@@ -456,6 +575,8 @@ func (mutator *mutator) register(ctx *Context) {
|
|||||||
handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator)
|
handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator)
|
||||||
} else if mutator.topDownMutator != nil {
|
} else if mutator.topDownMutator != nil {
|
||||||
handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
|
handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator)
|
||||||
|
} else if mutator.transitionMutator != nil {
|
||||||
|
blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator)
|
||||||
}
|
}
|
||||||
if mutator.parallel {
|
if mutator.parallel {
|
||||||
handle.Parallel()
|
handle.Parallel()
|
||||||
|
@@ -96,10 +96,11 @@ var singletons sortableComponents
|
|||||||
var preSingletons sortableComponents
|
var preSingletons sortableComponents
|
||||||
|
|
||||||
type mutator struct {
|
type mutator struct {
|
||||||
name string
|
name string
|
||||||
bottomUpMutator blueprint.BottomUpMutator
|
bottomUpMutator blueprint.BottomUpMutator
|
||||||
topDownMutator blueprint.TopDownMutator
|
topDownMutator blueprint.TopDownMutator
|
||||||
parallel bool
|
transitionMutator blueprint.TransitionMutator
|
||||||
|
parallel bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ sortableComponent = &mutator{}
|
var _ sortableComponent = &mutator{}
|
||||||
|
1
cc/cc.go
1
cc/cc.go
@@ -990,6 +990,7 @@ func (c *Module) Shared() bool {
|
|||||||
return library.shared()
|
return library.shared()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
|
panic(fmt.Errorf("Shared() called on non-library module: %q", c.BaseModuleName()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,13 +22,6 @@ type PlatformSanitizeable interface {
|
|||||||
// than left undefined.
|
// than left undefined.
|
||||||
IsSanitizerExplicitlyDisabled(t SanitizerType) bool
|
IsSanitizerExplicitlyDisabled(t SanitizerType) bool
|
||||||
|
|
||||||
// SanitizeDep returns true if the module is statically linked into another that is sanitized
|
|
||||||
// with the given sanitizer.
|
|
||||||
SanitizeDep(t SanitizerType) bool
|
|
||||||
|
|
||||||
// SetSanitizeDep marks a module as a static dependency of another module to be sanitized.
|
|
||||||
SetSanitizeDep(t SanitizerType)
|
|
||||||
|
|
||||||
// SetSanitizer enables or disables the specified sanitizer type if it's supported, otherwise this should panic.
|
// SetSanitizer enables or disables the specified sanitizer type if it's supported, otherwise this should panic.
|
||||||
SetSanitizer(t SanitizerType, b bool)
|
SetSanitizer(t SanitizerType, b bool)
|
||||||
|
|
||||||
|
407
cc/sanitize.go
407
cc/sanitize.go
@@ -153,9 +153,10 @@ func (t SanitizerType) name() string {
|
|||||||
|
|
||||||
func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
|
func (t SanitizerType) registerMutators(ctx android.RegisterMutatorsContext) {
|
||||||
switch t {
|
switch t {
|
||||||
case Asan, Hwasan, Fuzzer, scs, tsan, cfi:
|
case cfi, Hwasan, Asan, tsan, Fuzzer, scs:
|
||||||
ctx.TopDown(t.variationName()+"_deps", sanitizerDepsMutator(t))
|
sanitizer := &sanitizerSplitMutator{t}
|
||||||
ctx.BottomUp(t.variationName(), sanitizerMutator(t))
|
ctx.TopDown(t.variationName()+"_markapexes", sanitizer.markSanitizableApexesMutator)
|
||||||
|
ctx.Transition(t.variationName(), sanitizer)
|
||||||
case Memtag_heap, intOverflow:
|
case Memtag_heap, intOverflow:
|
||||||
// do nothing
|
// do nothing
|
||||||
default:
|
default:
|
||||||
@@ -276,7 +277,6 @@ type SanitizeUserProps struct {
|
|||||||
type SanitizeProperties struct {
|
type SanitizeProperties struct {
|
||||||
Sanitize SanitizeUserProps `android:"arch_variant"`
|
Sanitize SanitizeUserProps `android:"arch_variant"`
|
||||||
SanitizerEnabled bool `blueprint:"mutated"`
|
SanitizerEnabled bool `blueprint:"mutated"`
|
||||||
SanitizeDepTypes []SanitizerType `blueprint:"mutated"`
|
|
||||||
MinimalRuntimeDep bool `blueprint:"mutated"`
|
MinimalRuntimeDep bool `blueprint:"mutated"`
|
||||||
BuiltinsDep bool `blueprint:"mutated"`
|
BuiltinsDep bool `blueprint:"mutated"`
|
||||||
UbsanRuntimeDep bool `blueprint:"mutated"`
|
UbsanRuntimeDep bool `blueprint:"mutated"`
|
||||||
@@ -898,7 +898,7 @@ func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker {
|
|||||||
// Determines if the current module is a static library going to be captured
|
// Determines if the current module is a static library going to be captured
|
||||||
// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
|
// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
|
||||||
// except for ones which explicitly disable cfi.
|
// except for ones which explicitly disable cfi.
|
||||||
func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
|
func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool {
|
||||||
if snapshot.IsVendorProprietaryModule(mctx) {
|
if snapshot.IsVendorProprietaryModule(mctx) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -926,62 +926,232 @@ func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
|
|||||||
!c.IsSanitizerExplicitlyDisabled(cfi)
|
!c.IsSanitizerExplicitlyDisabled(cfi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate sanitizer requirements down from binaries
|
type sanitizerSplitMutator struct {
|
||||||
func sanitizerDepsMutator(t SanitizerType) func(android.TopDownMutatorContext) {
|
sanitizer SanitizerType
|
||||||
return func(mctx android.TopDownMutatorContext) {
|
}
|
||||||
if c, ok := mctx.Module().(PlatformSanitizeable); ok {
|
|
||||||
enabled := c.IsSanitizerEnabled(t)
|
// If an APEX is sanitized or not depends on whether it contains at least one
|
||||||
if t == cfi && needsCfiForVendorSnapshot(mctx) {
|
// sanitized module. Transition mutators cannot propagate information up the
|
||||||
// We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
|
// dependency graph this way, so we need an auxiliary mutator to do so.
|
||||||
// determine defaultVariation in sanitizerMutator below.
|
func (s *sanitizerSplitMutator) markSanitizableApexesMutator(ctx android.TopDownMutatorContext) {
|
||||||
// Instead, just mark SanitizeDep to forcefully create cfi variant.
|
if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
|
||||||
|
enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
|
||||||
|
ctx.VisitDirectDeps(func(dep android.Module) {
|
||||||
|
if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) {
|
||||||
enabled = true
|
enabled = true
|
||||||
c.SetSanitizeDep(t)
|
|
||||||
}
|
}
|
||||||
if enabled {
|
})
|
||||||
isSanitizableDependencyTag := c.SanitizableDepTagChecker()
|
|
||||||
mctx.WalkDeps(func(child, parent android.Module) bool {
|
if enabled {
|
||||||
if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
|
sanitizeable.EnableSanitizer(s.sanitizer.name())
|
||||||
return false
|
}
|
||||||
}
|
}
|
||||||
if d, ok := child.(PlatformSanitizeable); ok && d.SanitizePropDefined() &&
|
}
|
||||||
!d.SanitizeNever() &&
|
|
||||||
!d.IsSanitizerExplicitlyDisabled(t) {
|
func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
|
||||||
if t == cfi || t == Hwasan || t == scs || t == Asan {
|
if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
|
||||||
if d.StaticallyLinked() && d.SanitizerSupported(t) {
|
if s.sanitizer == cfi && needsCfiForVendorSnapshot(ctx) {
|
||||||
// Rust does not support some of these sanitizers, so we need to check if it's
|
return []string{"", s.sanitizer.variationName()}
|
||||||
// supported before setting this true.
|
}
|
||||||
d.SetSanitizeDep(t)
|
|
||||||
}
|
// If the given sanitizer is not requested in the .bp file for a module, it
|
||||||
} else {
|
// won't automatically build the sanitized variation.
|
||||||
d.SetSanitizeDep(t)
|
if !c.IsSanitizerEnabled(s.sanitizer) {
|
||||||
}
|
return []string{""}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
})
|
if c.Binary() {
|
||||||
|
// If a sanitizer is enabled for a binary, we do not build the version
|
||||||
|
// without the sanitizer
|
||||||
|
return []string{s.sanitizer.variationName()}
|
||||||
|
} else if c.StaticallyLinked() || c.Header() {
|
||||||
|
// For static libraries, we build both versions. Some Make modules
|
||||||
|
// apparently depend on this behavior.
|
||||||
|
return []string{"", s.sanitizer.variationName()}
|
||||||
|
} else {
|
||||||
|
// We only build the requested variation of dynamic libraries
|
||||||
|
return []string{s.sanitizer.variationName()}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := ctx.Module().(JniSanitizeable); ok {
|
||||||
|
// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
|
||||||
|
// that is short-circuited for now
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If an APEX has a sanitized dependency, we build the APEX in the sanitized
|
||||||
|
// variation. This is useful because such APEXes require extra dependencies.
|
||||||
|
if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
|
||||||
|
enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
|
||||||
|
if enabled {
|
||||||
|
return []string{s.sanitizer.variationName()}
|
||||||
|
} else {
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c, ok := ctx.Module().(*Module); ok {
|
||||||
|
//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
|
||||||
|
|
||||||
|
// Check if it's a snapshot module supporting sanitizer
|
||||||
|
if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
|
||||||
|
return []string{"", s.sanitizer.variationName()}
|
||||||
|
} else {
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{""}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sanitizerSplitMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
|
||||||
|
if c, ok := ctx.Module().(PlatformSanitizeable); ok {
|
||||||
|
if !c.SanitizableDepTagChecker()(ctx.DepTag()) {
|
||||||
|
// If the dependency is through a non-sanitizable tag, use the
|
||||||
|
// non-sanitized variation
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceVariation
|
||||||
|
} else if _, ok := ctx.Module().(JniSanitizeable); ok {
|
||||||
|
// TODO: this should call into JniSanitizable.IsSanitizerEnabledForJni but
|
||||||
|
// that is short-circuited for now
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
// Otherwise, do not rock the boat.
|
||||||
|
return sourceVariation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
|
||||||
|
if d, ok := ctx.Module().(PlatformSanitizeable); ok {
|
||||||
|
if dm, ok := ctx.Module().(*Module); ok {
|
||||||
|
if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
|
||||||
|
return incomingVariation
|
||||||
}
|
}
|
||||||
} else if jniSanitizeable, ok := mctx.Module().(JniSanitizeable); ok {
|
}
|
||||||
// If it's a Java module with native dependencies through jni,
|
|
||||||
// set the sanitizer for them
|
if !d.SanitizePropDefined() ||
|
||||||
if jniSanitizeable.IsSanitizerEnabledForJni(mctx, t.name()) {
|
d.SanitizeNever() ||
|
||||||
mctx.VisitDirectDeps(func(child android.Module) {
|
d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
|
||||||
if c, ok := child.(PlatformSanitizeable); ok &&
|
!d.SanitizerSupported(s.sanitizer) {
|
||||||
mctx.OtherModuleDependencyTag(child) == JniFuzzLibTag &&
|
// If a module opts out of a sanitizer, use its non-sanitized variation
|
||||||
c.SanitizePropDefined() &&
|
return ""
|
||||||
!c.SanitizeNever() &&
|
}
|
||||||
!c.IsSanitizerExplicitlyDisabled(t) {
|
|
||||||
c.SetSanitizeDep(t)
|
// Binaries are always built in the variation they requested.
|
||||||
}
|
if d.Binary() {
|
||||||
})
|
if d.IsSanitizerEnabled(s.sanitizer) {
|
||||||
|
return s.sanitizer.variationName()
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
|
}
|
||||||
// If an APEX module includes a lib which is enabled for a sanitizer T, then
|
|
||||||
// the APEX module is also enabled for the same sanitizer type.
|
// If a shared library requests to be sanitized, it will be built for that
|
||||||
mctx.VisitDirectDeps(func(child android.Module) {
|
// sanitizer. Otherwise, some sanitizers propagate through shared library
|
||||||
if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
|
// dependency edges, some do not.
|
||||||
sanitizeable.EnableSanitizer(t.name())
|
if !d.StaticallyLinked() && !d.Header() {
|
||||||
|
if d.IsSanitizerEnabled(s.sanitizer) {
|
||||||
|
return s.sanitizer.variationName()
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.sanitizer == cfi || s.sanitizer == Hwasan || s.sanitizer == scs || s.sanitizer == Asan {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static and header libraries inherit whether they are sanitized from the
|
||||||
|
// module they are linked into
|
||||||
|
return incomingVariation
|
||||||
|
} else if d, ok := ctx.Module().(Sanitizeable); ok {
|
||||||
|
// If an APEX contains a sanitized module, it will be built in the variation
|
||||||
|
// corresponding to that sanitizer.
|
||||||
|
enabled := d.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
|
||||||
|
if enabled {
|
||||||
|
return s.sanitizer.variationName()
|
||||||
|
}
|
||||||
|
|
||||||
|
return incomingVariation
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sanitizerSplitMutator) Mutate(mctx android.BottomUpMutatorContext, variationName string) {
|
||||||
|
sanitizerVariation := variationName == s.sanitizer.variationName()
|
||||||
|
|
||||||
|
if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
|
||||||
|
sanitizerEnabled := c.IsSanitizerEnabled(s.sanitizer)
|
||||||
|
|
||||||
|
oneMakeVariation := false
|
||||||
|
if c.StaticallyLinked() || c.Header() {
|
||||||
|
if s.sanitizer != cfi && s.sanitizer != scs && s.sanitizer != Hwasan {
|
||||||
|
// These sanitizers export only one variation to Make. For the rest,
|
||||||
|
// Make targets can depend on both the sanitized and non-sanitized
|
||||||
|
// versions.
|
||||||
|
oneMakeVariation = true
|
||||||
|
}
|
||||||
|
} else if !c.Binary() {
|
||||||
|
// Shared library. These are the sanitizers that do propagate through shared
|
||||||
|
// library dependencies and therefore can cause multiple variations of a
|
||||||
|
// shared library to be built.
|
||||||
|
if s.sanitizer != cfi && s.sanitizer != Hwasan && s.sanitizer != scs && s.sanitizer != Asan {
|
||||||
|
oneMakeVariation = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oneMakeVariation {
|
||||||
|
if sanitizerEnabled != sanitizerVariation {
|
||||||
|
c.SetPreventInstall()
|
||||||
|
c.SetHideFromMake()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sanitizerVariation {
|
||||||
|
c.SetSanitizer(s.sanitizer, true)
|
||||||
|
|
||||||
|
// CFI is incompatible with ASAN so disable it in ASAN variations
|
||||||
|
if s.sanitizer.incompatibleWithCfi() {
|
||||||
|
cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
|
||||||
|
if mctx.Device() && cfiSupported {
|
||||||
|
c.SetSanitizer(cfi, false)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// locate the asan libraries under /data/asan
|
||||||
|
if !c.Binary() && !c.StaticallyLinked() && !c.Header() && mctx.Device() && s.sanitizer == Asan && sanitizerEnabled {
|
||||||
|
c.SetInSanitizerDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.StaticallyLinked() && c.ExportedToMake() {
|
||||||
|
if s.sanitizer == Hwasan {
|
||||||
|
hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
|
||||||
|
} else if s.sanitizer == cfi {
|
||||||
|
cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if c.IsSanitizerEnabled(s.sanitizer) {
|
||||||
|
// Disable the sanitizer for the non-sanitized variation
|
||||||
|
c.SetSanitizer(s.sanitizer, false)
|
||||||
|
}
|
||||||
|
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
|
||||||
|
// If an APEX has sanitized dependencies, it gets a few more dependencies
|
||||||
|
if sanitizerVariation {
|
||||||
|
sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
|
||||||
|
}
|
||||||
|
} else if c, ok := mctx.Module().(*Module); ok {
|
||||||
|
if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerEnabled(s.sanitizer) {
|
||||||
|
c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation)
|
||||||
|
|
||||||
|
// Export the static lib name to make
|
||||||
|
if c.static() && c.ExportedToMake() {
|
||||||
|
if s.sanitizer == cfi {
|
||||||
|
// use BaseModuleName which is the name for Make.
|
||||||
|
cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1307,16 +1477,6 @@ func (c *Module) IsSanitizerEnabled(t SanitizerType) bool {
|
|||||||
return c.sanitize.isSanitizerEnabled(t)
|
return c.sanitize.isSanitizerEnabled(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Module) SanitizeDep(t SanitizerType) bool {
|
|
||||||
for _, e := range c.sanitize.Properties.SanitizeDepTypes {
|
|
||||||
if t == e {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Module) StaticallyLinked() bool {
|
func (c *Module) StaticallyLinked() bool {
|
||||||
return c.static()
|
return c.static()
|
||||||
}
|
}
|
||||||
@@ -1333,123 +1493,8 @@ func (c *Module) SetSanitizer(t SanitizerType, b bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Module) SetSanitizeDep(t SanitizerType) {
|
|
||||||
if !c.SanitizeDep(t) {
|
|
||||||
c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ PlatformSanitizeable = (*Module)(nil)
|
var _ PlatformSanitizeable = (*Module)(nil)
|
||||||
|
|
||||||
// Create sanitized variants for modules that need them
|
|
||||||
func sanitizerMutator(t SanitizerType) func(android.BottomUpMutatorContext) {
|
|
||||||
return func(mctx android.BottomUpMutatorContext) {
|
|
||||||
if c, ok := mctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
|
|
||||||
|
|
||||||
// Make sure we're not setting CFI to any value if it's not supported.
|
|
||||||
cfiSupported := mctx.Module().(PlatformSanitizeable).SanitizerSupported(cfi)
|
|
||||||
|
|
||||||
if c.Binary() && c.IsSanitizerEnabled(t) {
|
|
||||||
modules := mctx.CreateVariations(t.variationName())
|
|
||||||
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
|
|
||||||
} else if c.IsSanitizerEnabled(t) || c.SanitizeDep(t) {
|
|
||||||
isSanitizerEnabled := c.IsSanitizerEnabled(t)
|
|
||||||
if c.StaticallyLinked() || c.Header() || t == Fuzzer {
|
|
||||||
// Static and header libs are split into non-sanitized and sanitized variants.
|
|
||||||
// Shared libs are not split. However, for asan and fuzzer, we split even for shared
|
|
||||||
// libs because a library sanitized for asan/fuzzer can't be linked from a library
|
|
||||||
// that isn't sanitized for asan/fuzzer.
|
|
||||||
//
|
|
||||||
// Note for defaultVariation: since we don't split for shared libs but for static/header
|
|
||||||
// libs, it is possible for the sanitized variant of a static/header lib to depend
|
|
||||||
// on non-sanitized variant of a shared lib. Such unfulfilled variation causes an
|
|
||||||
// error when the module is split. defaultVariation is the name of the variation that
|
|
||||||
// will be used when such a dangling dependency occurs during the split of the current
|
|
||||||
// module. By setting it to the name of the sanitized variation, the dangling dependency
|
|
||||||
// is redirected to the sanitized variant of the dependent module.
|
|
||||||
defaultVariation := t.variationName()
|
|
||||||
// Not all PlatformSanitizeable modules support the CFI sanitizer
|
|
||||||
mctx.SetDefaultDependencyVariation(&defaultVariation)
|
|
||||||
|
|
||||||
modules := mctx.CreateVariations("", t.variationName())
|
|
||||||
modules[0].(PlatformSanitizeable).SetSanitizer(t, false)
|
|
||||||
modules[1].(PlatformSanitizeable).SetSanitizer(t, true)
|
|
||||||
|
|
||||||
if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
|
|
||||||
// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
|
|
||||||
// are incompatible with cfi
|
|
||||||
modules[1].(PlatformSanitizeable).SetSanitizer(cfi, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For cfi/scs/hwasan, we can export both sanitized and un-sanitized variants
|
|
||||||
// to Make, because the sanitized version has a different suffix in name.
|
|
||||||
// For other types of sanitizers, suppress the variation that is disabled.
|
|
||||||
if t != cfi && t != scs && t != Hwasan {
|
|
||||||
if isSanitizerEnabled {
|
|
||||||
modules[0].(PlatformSanitizeable).SetPreventInstall()
|
|
||||||
modules[0].(PlatformSanitizeable).SetHideFromMake()
|
|
||||||
} else {
|
|
||||||
modules[1].(PlatformSanitizeable).SetPreventInstall()
|
|
||||||
modules[1].(PlatformSanitizeable).SetHideFromMake()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Export the static lib name to make
|
|
||||||
if c.StaticallyLinked() && c.ExportedToMake() {
|
|
||||||
if t == cfi {
|
|
||||||
cfiStaticLibs(mctx.Config()).add(c, c.Module().Name())
|
|
||||||
} else if t == Hwasan {
|
|
||||||
hwasanStaticLibs(mctx.Config()).add(c, c.Module().Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Shared libs are not split. Only the sanitized variant is created.
|
|
||||||
modules := mctx.CreateVariations(t.variationName())
|
|
||||||
modules[0].(PlatformSanitizeable).SetSanitizer(t, true)
|
|
||||||
|
|
||||||
// locate the asan libraries under /data/asan
|
|
||||||
if mctx.Device() && t == Asan && isSanitizerEnabled {
|
|
||||||
modules[0].(PlatformSanitizeable).SetInSanitizerDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
if mctx.Device() && t.incompatibleWithCfi() && cfiSupported {
|
|
||||||
// TODO: Make sure that cfi mutator runs "after" any of the sanitizers that
|
|
||||||
// are incompatible with cfi
|
|
||||||
modules[0].(PlatformSanitizeable).SetSanitizer(cfi, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx.Config(), t.name()) {
|
|
||||||
// APEX fuzz modules fall here
|
|
||||||
sanitizeable.AddSanitizerDependencies(mctx, t.name())
|
|
||||||
mctx.CreateVariations(t.variationName())
|
|
||||||
} else if _, ok := mctx.Module().(JniSanitizeable); ok {
|
|
||||||
// Java fuzz modules fall here
|
|
||||||
mctx.CreateVariations(t.variationName())
|
|
||||||
} else if c, ok := mctx.Module().(*Module); ok {
|
|
||||||
//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
|
|
||||||
|
|
||||||
// Check if it's a snapshot module supporting sanitizer
|
|
||||||
if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
|
|
||||||
// Set default variation as above.
|
|
||||||
defaultVariation := t.variationName()
|
|
||||||
mctx.SetDefaultDependencyVariation(&defaultVariation)
|
|
||||||
modules := mctx.CreateVariations("", t.variationName())
|
|
||||||
modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
|
|
||||||
modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)
|
|
||||||
|
|
||||||
// Export the static lib name to make
|
|
||||||
if c.static() && c.ExportedToMake() {
|
|
||||||
if t == cfi {
|
|
||||||
// use BaseModuleName which is the name for Make.
|
|
||||||
cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type sanitizerStaticLibsMap struct {
|
type sanitizerStaticLibsMap struct {
|
||||||
// libsMap contains one list of modules per each image and each arch.
|
// libsMap contains one list of modules per each image and each arch.
|
||||||
// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
|
// e.g. libs[vendor]["arm"] contains arm modules installed to vendor
|
||||||
|
@@ -49,8 +49,7 @@ type SanitizeProperties struct {
|
|||||||
Memtag_heap *bool `android:"arch_variant"`
|
Memtag_heap *bool `android:"arch_variant"`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SanitizerEnabled bool `blueprint:"mutated"`
|
SanitizerEnabled bool `blueprint:"mutated"`
|
||||||
SanitizeDepTypes []cc.SanitizerType `blueprint:"mutated"`
|
|
||||||
|
|
||||||
// Used when we need to place libraries in their own directory, such as ASAN.
|
// Used when we need to place libraries in their own directory, such as ASAN.
|
||||||
InSanitizerDir bool `blueprint:"mutated"`
|
InSanitizerDir bool `blueprint:"mutated"`
|
||||||
@@ -444,28 +443,12 @@ func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
|
|||||||
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
|
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *Module) SanitizeDep(t cc.SanitizerType) bool {
|
|
||||||
for _, e := range mod.sanitize.Properties.SanitizeDepTypes {
|
|
||||||
if t == e {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) {
|
func (mod *Module) SetSanitizer(t cc.SanitizerType, b bool) {
|
||||||
if !Bool(mod.sanitize.Properties.Sanitize.Never) {
|
if !Bool(mod.sanitize.Properties.Sanitize.Never) {
|
||||||
mod.sanitize.SetSanitizer(t, b)
|
mod.sanitize.SetSanitizer(t, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Module) SetSanitizeDep(t cc.SanitizerType) {
|
|
||||||
if !c.SanitizeDep(t) {
|
|
||||||
c.sanitize.Properties.SanitizeDepTypes = append(c.sanitize.Properties.SanitizeDepTypes, t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *Module) StaticallyLinked() bool {
|
func (mod *Module) StaticallyLinked() bool {
|
||||||
if lib, ok := mod.compiler.(libraryInterface); ok {
|
if lib, ok := mod.compiler.(libraryInterface); ok {
|
||||||
return lib.rlib() || lib.static()
|
return lib.rlib() || lib.static()
|
||||||
|
Reference in New Issue
Block a user