Merge "rust: Package shared libraries with fuzzer zips"
This commit is contained in:
136
cc/fuzz.go
136
cc/fuzz.go
@@ -79,54 +79,21 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
|
|||||||
return flags
|
return flags
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function performs a breadth-first search over the provided module's
|
func UnstrippedOutputFile(module android.Module) android.Path {
|
||||||
// dependencies using `visitDirectDeps` to enumerate all shared library
|
if mod, ok := module.(LinkableInterface); ok {
|
||||||
// dependencies. We require breadth-first expansion, as otherwise we may
|
return mod.UnstrippedOutputFile()
|
||||||
// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
|
|
||||||
// from a dependency. This may cause issues when dependencies have explicit
|
|
||||||
// sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
|
|
||||||
func collectAllSharedDependencies(ctx android.SingletonContext, module android.Module) android.Paths {
|
|
||||||
var fringe []android.Module
|
|
||||||
|
|
||||||
seen := make(map[string]bool)
|
|
||||||
|
|
||||||
// Enumerate the first level of dependencies, as we discard all non-library
|
|
||||||
// modules in the BFS loop below.
|
|
||||||
ctx.VisitDirectDeps(module, func(dep android.Module) {
|
|
||||||
if isValidSharedDependency(dep) {
|
|
||||||
fringe = append(fringe, dep)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
var sharedLibraries android.Paths
|
|
||||||
|
|
||||||
for i := 0; i < len(fringe); i++ {
|
|
||||||
module := fringe[i]
|
|
||||||
if seen[module.Name()] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[module.Name()] = true
|
|
||||||
|
|
||||||
ccModule := module.(*Module)
|
|
||||||
sharedLibraries = append(sharedLibraries, ccModule.UnstrippedOutputFile())
|
|
||||||
ctx.VisitDirectDeps(module, func(dep android.Module) {
|
|
||||||
if isValidSharedDependency(dep) && !seen[dep.Name()] {
|
|
||||||
fringe = append(fringe, dep)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
panic("UnstrippedOutputFile called on non-LinkableInterface module: " + module.Name())
|
||||||
return sharedLibraries
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function takes a module and determines if it is a unique shared library
|
// IsValidSharedDependency takes a module and determines if it is a unique shared library
|
||||||
// that should be installed in the fuzz target output directories. This function
|
// that should be installed in the fuzz target output directories. This function
|
||||||
// returns true, unless:
|
// returns true, unless:
|
||||||
// - The module is not an installable shared library, or
|
// - The module is not an installable shared library, or
|
||||||
// - The module is a header or stub, or
|
// - The module is a header or stub, or
|
||||||
// - The module is a prebuilt and its source is available, or
|
// - The module is a prebuilt and its source is available, or
|
||||||
// - The module is a versioned member of an SDK snapshot.
|
// - The module is a versioned member of an SDK snapshot.
|
||||||
func isValidSharedDependency(dependency android.Module) bool {
|
func IsValidSharedDependency(dependency android.Module) bool {
|
||||||
// TODO(b/144090547): We should be parsing these modules using
|
// TODO(b/144090547): We should be parsing these modules using
|
||||||
// ModuleDependencyTag instead of the current brute-force checking.
|
// ModuleDependencyTag instead of the current brute-force checking.
|
||||||
|
|
||||||
@@ -246,7 +213,7 @@ func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
|
|||||||
}
|
}
|
||||||
seen[child.Name()] = true
|
seen[child.Name()] = true
|
||||||
|
|
||||||
if isValidSharedDependency(child) {
|
if IsValidSharedDependency(child) {
|
||||||
sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
|
sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -304,7 +271,6 @@ func NewFuzz(hod android.HostOrDeviceSupported) *Module {
|
|||||||
// their architecture & target/host specific zip file.
|
// their architecture & target/host specific zip file.
|
||||||
type ccFuzzPackager struct {
|
type ccFuzzPackager struct {
|
||||||
fuzz.FuzzPackager
|
fuzz.FuzzPackager
|
||||||
sharedLibInstallStrings []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fuzzPackagingFactory() android.Singleton {
|
func fuzzPackagingFactory() android.Singleton {
|
||||||
@@ -317,14 +283,14 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
// archive}).
|
// archive}).
|
||||||
archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
|
archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip)
|
||||||
|
|
||||||
// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
|
|
||||||
// multiple fuzzers that depend on the same shared library.
|
|
||||||
sharedLibraryInstalled := make(map[string]bool)
|
|
||||||
|
|
||||||
// List of individual fuzz targets, so that 'make fuzz' also installs the targets
|
// List of individual fuzz targets, so that 'make fuzz' also installs the targets
|
||||||
// to the correct output directories as well.
|
// to the correct output directories as well.
|
||||||
s.FuzzTargets = make(map[string]bool)
|
s.FuzzTargets = make(map[string]bool)
|
||||||
|
|
||||||
|
// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
|
||||||
|
// multiple fuzzers that depend on the same shared library.
|
||||||
|
sharedLibraryInstalled := make(map[string]bool)
|
||||||
|
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
ccModule, ok := module.(*Module)
|
ccModule, ok := module.(*Module)
|
||||||
if !ok || ccModule.Properties.PreventInstall {
|
if !ok || ccModule.Properties.PreventInstall {
|
||||||
@@ -351,7 +317,7 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
|
archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()}
|
||||||
|
|
||||||
// Grab the list of required shared libraries.
|
// Grab the list of required shared libraries.
|
||||||
sharedLibraries := collectAllSharedDependencies(ctx, module)
|
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, UnstrippedOutputFile, IsValidSharedDependency)
|
||||||
|
|
||||||
var files []fuzz.FileToZip
|
var files []fuzz.FileToZip
|
||||||
builder := android.NewRuleBuilder(pctx, ctx)
|
builder := android.NewRuleBuilder(pctx, ctx)
|
||||||
@@ -359,39 +325,8 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
// Package the corpus, data, dict and config into a zipfile.
|
// Package the corpus, data, dict and config into a zipfile.
|
||||||
files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
|
files = s.PackageArtifacts(ctx, module, fuzzModule.fuzzPackagedModule, archDir, builder)
|
||||||
|
|
||||||
// Find and mark all the transiently-dependent shared libraries for
|
// Package shared libraries
|
||||||
// packaging.
|
files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, &sharedLibraryInstalled)...)
|
||||||
for _, library := range sharedLibraries {
|
|
||||||
files = append(files, fuzz.FileToZip{library, "lib"})
|
|
||||||
|
|
||||||
// For each architecture-specific shared library dependency, we need to
|
|
||||||
// install it to the output directory. Setup the install destination here,
|
|
||||||
// which will be used by $(copy-many-files) in the Make backend.
|
|
||||||
installDestination := sharedLibraryInstallLocation(
|
|
||||||
library, ccModule.Host(), archString)
|
|
||||||
if sharedLibraryInstalled[installDestination] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sharedLibraryInstalled[installDestination] = true
|
|
||||||
|
|
||||||
// Escape all the variables, as the install destination here will be called
|
|
||||||
// via. $(eval) in Make.
|
|
||||||
installDestination = strings.ReplaceAll(
|
|
||||||
installDestination, "$", "$$")
|
|
||||||
s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
|
|
||||||
library.String()+":"+installDestination)
|
|
||||||
|
|
||||||
// Ensure that on device, the library is also reinstalled to the /symbols/
|
|
||||||
// dir. Symbolized DSO's are always installed to the device when fuzzing, but
|
|
||||||
// we want symbolization tools (like `stack`) to be able to find the symbols
|
|
||||||
// in $ANDROID_PRODUCT_OUT/symbols automagically.
|
|
||||||
if !ccModule.Host() {
|
|
||||||
symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
|
|
||||||
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
|
|
||||||
s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
|
|
||||||
library.String()+":"+symbolsInstallDestination)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The executable.
|
// The executable.
|
||||||
files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
|
files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""})
|
||||||
@@ -409,15 +344,54 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
|
func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
|
||||||
packages := s.Packages.Strings()
|
packages := s.Packages.Strings()
|
||||||
sort.Strings(packages)
|
sort.Strings(packages)
|
||||||
sort.Strings(s.sharedLibInstallStrings)
|
sort.Strings(s.FuzzPackager.SharedLibInstallStrings)
|
||||||
// TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
|
// TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's
|
||||||
// ready to handle phony targets created in Soong. In the meantime, this
|
// ready to handle phony targets created in Soong. In the meantime, this
|
||||||
// exports the phony 'fuzz' target and dependencies on packages to
|
// exports the phony 'fuzz' target and dependencies on packages to
|
||||||
// core/main.mk so that we can use dist-for-goals.
|
// core/main.mk so that we can use dist-for-goals.
|
||||||
ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
|
ctx.Strict("SOONG_FUZZ_PACKAGING_ARCH_MODULES", strings.Join(packages, " "))
|
||||||
ctx.Strict("FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
|
ctx.Strict("FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
|
||||||
strings.Join(s.sharedLibInstallStrings, " "))
|
strings.Join(s.FuzzPackager.SharedLibInstallStrings, " "))
|
||||||
|
|
||||||
// Preallocate the slice of fuzz targets to minimise memory allocations.
|
// Preallocate the slice of fuzz targets to minimise memory allocations.
|
||||||
s.PreallocateSlice(ctx, "ALL_FUZZ_TARGETS")
|
s.PreallocateSlice(ctx, "ALL_FUZZ_TARGETS")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
|
||||||
|
// packaging.
|
||||||
|
func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
|
||||||
|
var files []fuzz.FileToZip
|
||||||
|
|
||||||
|
for _, library := range sharedLibraries {
|
||||||
|
files = append(files, fuzz.FileToZip{library, "lib"})
|
||||||
|
|
||||||
|
// For each architecture-specific shared library dependency, we need to
|
||||||
|
// install it to the output directory. Setup the install destination here,
|
||||||
|
// which will be used by $(copy-many-files) in the Make backend.
|
||||||
|
installDestination := sharedLibraryInstallLocation(
|
||||||
|
library, module.Host(), archString)
|
||||||
|
if (*sharedLibraryInstalled)[installDestination] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
(*sharedLibraryInstalled)[installDestination] = true
|
||||||
|
|
||||||
|
// Escape all the variables, as the install destination here will be called
|
||||||
|
// via. $(eval) in Make.
|
||||||
|
installDestination = strings.ReplaceAll(
|
||||||
|
installDestination, "$", "$$")
|
||||||
|
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
|
||||||
|
library.String()+":"+installDestination)
|
||||||
|
|
||||||
|
// Ensure that on device, the library is also reinstalled to the /symbols/
|
||||||
|
// dir. Symbolized DSO's are always installed to the device when fuzzing, but
|
||||||
|
// we want symbolization tools (like `stack`) to be able to find the symbols
|
||||||
|
// in $ANDROID_PRODUCT_OUT/symbols automagically.
|
||||||
|
if !module.Host() {
|
||||||
|
symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
|
||||||
|
symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
|
||||||
|
s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
|
||||||
|
library.String()+":"+symbolsInstallDestination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
@@ -110,6 +110,7 @@ type LinkableInterface interface {
|
|||||||
BaseModuleName() string
|
BaseModuleName() string
|
||||||
|
|
||||||
OutputFile() android.OptionalPath
|
OutputFile() android.OptionalPath
|
||||||
|
UnstrippedOutputFile() android.Path
|
||||||
CoverageFiles() android.Paths
|
CoverageFiles() android.Paths
|
||||||
|
|
||||||
NonCcVariants() bool
|
NonCcVariants() bool
|
||||||
|
@@ -42,8 +42,9 @@ type FuzzModule struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FuzzPackager struct {
|
type FuzzPackager struct {
|
||||||
Packages android.Paths
|
Packages android.Paths
|
||||||
FuzzTargets map[string]bool
|
FuzzTargets map[string]bool
|
||||||
|
SharedLibInstallStrings []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileToZip struct {
|
type FileToZip struct {
|
||||||
@@ -251,3 +252,42 @@ func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets str
|
|||||||
sort.Strings(fuzzTargets)
|
sort.Strings(fuzzTargets)
|
||||||
ctx.Strict(targets, strings.Join(fuzzTargets, " "))
|
ctx.Strict(targets, strings.Join(fuzzTargets, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CollectAllSharedDependencies performs a breadth-first search over the provided module's
|
||||||
|
// dependencies using `visitDirectDeps` to enumerate all shared library
|
||||||
|
// dependencies. We require breadth-first expansion, as otherwise we may
|
||||||
|
// incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
|
||||||
|
// from a dependency. This may cause issues when dependencies have explicit
|
||||||
|
// sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
|
||||||
|
func CollectAllSharedDependencies(ctx android.SingletonContext, module android.Module, unstrippedOutputFile func(module android.Module) android.Path, isValidSharedDependency func(dependency android.Module) bool) android.Paths {
|
||||||
|
var fringe []android.Module
|
||||||
|
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
|
||||||
|
// Enumerate the first level of dependencies, as we discard all non-library
|
||||||
|
// modules in the BFS loop below.
|
||||||
|
ctx.VisitDirectDeps(module, func(dep android.Module) {
|
||||||
|
if isValidSharedDependency(dep) {
|
||||||
|
fringe = append(fringe, dep)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var sharedLibraries android.Paths
|
||||||
|
|
||||||
|
for i := 0; i < len(fringe); i++ {
|
||||||
|
module := fringe[i]
|
||||||
|
if seen[module.Name()] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[module.Name()] = true
|
||||||
|
|
||||||
|
sharedLibraries = append(sharedLibraries, unstrippedOutputFile(module))
|
||||||
|
ctx.VisitDirectDeps(module, func(dep android.Module) {
|
||||||
|
if isValidSharedDependency(dep) && !seen[dep.Name()] {
|
||||||
|
fringe = append(fringe, dep)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedLibraries
|
||||||
|
}
|
||||||
|
10
rust/fuzz.go
10
rust/fuzz.go
@@ -111,6 +111,10 @@ func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
// List of individual fuzz targets.
|
// List of individual fuzz targets.
|
||||||
s.FuzzTargets = make(map[string]bool)
|
s.FuzzTargets = make(map[string]bool)
|
||||||
|
|
||||||
|
// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
|
||||||
|
// multiple fuzzers that depend on the same shared library.
|
||||||
|
sharedLibraryInstalled := make(map[string]bool)
|
||||||
|
|
||||||
ctx.VisitAllModules(func(module android.Module) {
|
ctx.VisitAllModules(func(module android.Module) {
|
||||||
// Discard non-fuzz targets.
|
// Discard non-fuzz targets.
|
||||||
rustModule, ok := module.(*Module)
|
rustModule, ok := module.(*Module)
|
||||||
@@ -145,6 +149,12 @@ func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
|
|||||||
// The executable.
|
// The executable.
|
||||||
files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
|
files = append(files, fuzz.FileToZip{rustModule.unstrippedOutputFile.Path(), ""})
|
||||||
|
|
||||||
|
// Grab the list of required shared libraries.
|
||||||
|
sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, cc.UnstrippedOutputFile, cc.IsValidSharedDependency)
|
||||||
|
|
||||||
|
// Package shared libraries
|
||||||
|
files = append(files, cc.GetSharedLibsToZip(sharedLibraries, rustModule, &s.FuzzPackager, archString, &sharedLibraryInstalled)...)
|
||||||
|
|
||||||
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
|
archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
|
@@ -594,6 +594,13 @@ func (mod *Module) CcLibraryInterface() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *Module) UnstrippedOutputFile() android.Path {
|
||||||
|
if mod.unstrippedOutputFile.Valid() {
|
||||||
|
return mod.unstrippedOutputFile.Path()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) IncludeDirs() android.Paths {
|
func (mod *Module) IncludeDirs() android.Paths {
|
||||||
if mod.compiler != nil {
|
if mod.compiler != nil {
|
||||||
if library, ok := mod.compiler.(*libraryDecorator); ok {
|
if library, ok := mod.compiler.(*libraryDecorator); ok {
|
||||||
|
Reference in New Issue
Block a user