From a2aaa2fdefa8496820a6e9910765b8f2de2020b2 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 12:41:50 -0700 Subject: [PATCH 1/6] Fix panics when target arch is riscv64 Fix panics in api_level.go and apex.go when using riscv64 as the target arch. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Change-Id: I85c7685f3d14fa2dc7ffbcdea7f490feca304ef7 --- apex/apex.go | 5 +++++ cc/api_level.go | 2 ++ java/app_set.go | 9 +++++---- rust/config/riscv64_device.go | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index 2e54e7e6a..8bad6edfa 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -286,6 +286,9 @@ type apexArchBundleProperties struct { Arm64 struct { ApexNativeDependencies } + Riscv64 struct { + ApexNativeDependencies + } X86 struct { ApexNativeDependencies } @@ -787,6 +790,8 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { depsList = append(depsList, a.archProperties.Arch.Arm.ApexNativeDependencies) case android.Arm64: depsList = append(depsList, a.archProperties.Arch.Arm64.ApexNativeDependencies) + case android.Riscv64: + depsList = append(depsList, a.archProperties.Arch.Riscv64.ApexNativeDependencies) case android.X86: depsList = append(depsList, a.archProperties.Arch.X86.ApexNativeDependencies) case android.X86_64: diff --git a/cc/api_level.go b/cc/api_level.go index fd145a9e2..8c2b2c2ac 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -28,6 +28,8 @@ func minApiForArch(ctx android.BaseModuleContext, return ctx.Config().MinSupportedSdkVersion() case android.Arm64, android.X86_64: return android.FirstLp64Version + case android.Riscv64: + return android.FutureApiLevel default: panic(fmt.Errorf("Unknown arch %q", arch)) } diff --git a/java/app_set.go b/java/app_set.go index 694b1670e..d99fadb34 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -90,10 +90,11 @@ func (as *AndroidAppSet) APKCertsFile() android.Path { } var TargetCpuAbi = map[string]string{ - "arm": "ARMEABI_V7A", - "arm64": "ARM64_V8A", - "x86": "X86", - "x86_64": "X86_64", + "arm": "ARMEABI_V7A", + "arm64": "ARM64_V8A", + "riscv64": "RISCV64", + "x86": "X86", + "x86_64": "X86_64", } func SupportedAbis(ctx android.ModuleContext) []string { diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go index 3b41a10ad..d014dbf8b 100644 --- a/rust/config/riscv64_device.go +++ b/rust/config/riscv64_device.go @@ -25,7 +25,7 @@ var ( Riscv64ArchFeatureRustFlags = map[string][]string{"": {}} Riscv64LinkFlags = []string{} - Riscv64ArchVariantRustFlags = map[string][]string{} + Riscv64ArchVariantRustFlags = map[string][]string{"": {}} ) func init() { From 14ec66c2fba30e951b175d2a70c7cf62438eb5d3 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 21:02:27 -0700 Subject: [PATCH 2/6] Make OutputFileForModule work for AllowMissingDependencies Report missing output files as missing dependencies when AllowMissingDependencies is enabled. This will fix AllowMissingDependencies builds where a dependency module is present but missing support for a specific architecture. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Test: TestOutputFileForModule Change-Id: I95e96e3e7cb3df7bf678ed628b45baf659addbad --- android/android_test.go | 26 ++++++++++++- android/module.go | 27 +++++++++---- android/module_test.go | 86 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 9 deletions(-) diff --git a/android/android_test.go b/android/android_test.go index fb82e3765..64ceedc4d 100644 --- a/android/android_test.go +++ b/android/android_test.go @@ -15,10 +15,32 @@ package android import ( + "io/ioutil" "os" "testing" ) -func TestMain(m *testing.M) { - os.Exit(m.Run()) +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "android_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) } diff --git a/android/module.go b/android/module.go index a150e6191..68d9f8e75 100644 --- a/android/module.go +++ b/android/module.go @@ -3546,10 +3546,29 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P reportPathError(ctx, err) return nil } + if len(paths) == 0 { + type addMissingDependenciesIntf interface { + AddMissingDependencies([]string) + OtherModuleName(blueprint.Module) string + } + if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() { + mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)}) + } else { + ReportPathErrorf(ctx, "failed to get output files from module %q", pathContextName(ctx, module)) + } + // Return a fake output file to avoid nil dereferences of Path objects later. + // This should never get used for an actual build as the error or missing + // dependency has already been reported. + p, err := pathForSource(ctx, filepath.Join("missing_output_file", pathContextName(ctx, module))) + if err != nil { + reportPathError(ctx, err) + return nil + } + return p + } if len(paths) > 1 { ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) - return nil } return paths[0] } @@ -3561,18 +3580,12 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) return nil, fmt.Errorf("failed to get output file from module %q: %s", pathContextName(ctx, module), err.Error()) } - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) } paths := sourceFileProducer.Srcs() - if len(paths) == 0 { - return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) - } return paths, nil } else { return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module)) diff --git a/android/module_test.go b/android/module_test.go index 0580bef24..1ca742213 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -15,6 +15,7 @@ package android import ( + "github.com/google/blueprint" "path/filepath" "runtime" "testing" @@ -978,3 +979,88 @@ func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { }) } } + +type fakeBlueprintModule struct{} + +func (fakeBlueprintModule) Name() string { return "foo" } + +func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} + +type sourceProducerTestModule struct { + fakeBlueprintModule + source Path +} + +func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } + +type outputFileProducerTestModule struct { + fakeBlueprintModule + output map[string]Path + error map[string]error +} + +func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { + return PathsIfNonNil(o.output[tag]), o.error[tag] +} + +type pathContextAddMissingDependenciesWrapper struct { + PathContext + missingDeps []string +} + +func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { + p.missingDeps = append(p.missingDeps, deps...) +} +func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { + return module.Name() +} + +func TestOutputFileForModule(t *testing.T) { + testcases := []struct { + name string + module blueprint.Module + tag string + env map[string]string + config func(*config) + expected string + missingDeps []string + }{ + { + name: "SourceFileProducer", + module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer", + module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, + expected: "foo.txt", + }, + { + name: "OutputFileProducer_tag", + module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, + tag: "foo", + expected: "foo.txt", + }, + { + name: "OutputFileProducer_AllowMissingDependencies", + config: func(config *config) { + config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) + }, + module: &outputFileProducerTestModule{}, + missingDeps: []string{"foo"}, + expected: "missing_output_file/foo", + }, + } + for _, tt := range testcases { + config := TestConfig(buildDir, tt.env, "", nil) + if tt.config != nil { + tt.config(config.config) + } + ctx := &pathContextAddMissingDependenciesWrapper{ + PathContext: PathContextForTesting(config), + } + got := OutputFileForModule(ctx, tt.module, tt.tag) + AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) + AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) + } +} From 725eac60a241f19ca507dd894499a009a06ecf50 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 15:31:29 -0700 Subject: [PATCH 3/6] Add AllowMissingDependencies support for prebuilt_etc module with no src property Arch-specific prebuilt_etc modules may be missing source files for new architectures. Allow build analysis to continue when there is no source file when AllowMissingDependencies is set. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Test: TestPrebuiltEtcAllowMissingDependencies Change-Id: I647c7305339e3ed80283be5e59e6f4ef15ae2384 --- etc/prebuilt_etc.go | 44 ++++++++++++++++++++++++---------------- etc/prebuilt_etc_test.go | 24 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 362a8ef3c..baad58eed 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -296,27 +296,37 @@ func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool { } func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if p.properties.Src == nil { - ctx.PropertyErrorf("src", "missing prebuilt source file") - return - } - p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src)) - - // Determine the output file basename. - // If Filename is set, use the name specified by the property. - // If Filename_from_src is set, use the source file name. - // Otherwise use the module name. filename := proptools.String(p.properties.Filename) filenameFromSrc := proptools.Bool(p.properties.Filename_from_src) - if filename != "" { - if filenameFromSrc { - ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") - return + if p.properties.Src != nil { + p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src)) + + // Determine the output file basename. + // If Filename is set, use the name specified by the property. + // If Filename_from_src is set, use the source file name. + // Otherwise use the module name. + if filename != "" { + if filenameFromSrc { + ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true") + return + } + } else if filenameFromSrc { + filename = p.sourceFilePath.Base() + } else { + filename = ctx.ModuleName() + } + } else if ctx.Config().AllowMissingDependencies() { + // If no srcs was set and AllowMissingDependencies is enabled then + // mark the module as missing dependencies and set a fake source path + // and file name. + ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"}) + p.sourceFilePath = android.PathForModuleSrc(ctx) + if filename == "" { + filename = ctx.ModuleName() } - } else if filenameFromSrc { - filename = p.sourceFilePath.Base() } else { - filename = ctx.ModuleName() + ctx.PropertyErrorf("src", "missing prebuilt source file") + return } p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index cf1f6d717..a6477dd6a 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -195,6 +195,30 @@ func TestPrebuiltEtcHost(t *testing.T) { } } +func TestPrebuiltEtcAllowMissingDependencies(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForPrebuiltEtcTest, + android.PrepareForTestDisallowNonExistentPaths, + android.FixtureModifyConfig( + func(config android.Config) { + config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) + }), + ).RunTestWithBp(t, ` + prebuilt_etc { + name: "foo.conf", + filename_from_src: true, + arch: { + x86: { + src: "x86.conf", + }, + }, + } + `) + + android.AssertStringEquals(t, "expected error rule", "android/soong/android.Error", + result.ModuleForTests("foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String()) +} + func TestPrebuiltRootInstallDirPath(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` prebuilt_root { From 1d4871596197b8e954a1f34ae5301349f6ea862b Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 19:14:46 -0700 Subject: [PATCH 4/6] Support AllowMissingDependencies for apex dependencies Use android.OutputFileForModule instead of cc.Module.OutputFile, which will already handle the AllowMissingDependencies case. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Change-Id: I605ae9afe06ac450adec1d2a856e529e45ed5cb5 --- apex/apex.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index 8bad6edfa..01d74ae8c 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1564,7 +1564,7 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, h dirInApex = filepath.Join(dirInApex, "bionic") } - fileToCopy := ccMod.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, ccMod, "") androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod) } @@ -1575,7 +1575,7 @@ func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFil dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath) } dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath()) - fileToCopy := cc.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, cc, "") androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc) af.symlinks = cc.Symlinks() @@ -1588,7 +1588,7 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } - fileToCopy := rustm.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm) return af @@ -1607,7 +1607,7 @@ func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) a if rustm.Target().NativeBridge == android.NativeBridgeEnabled { dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath) } - fileToCopy := rustm.OutputFile().Path() + fileToCopy := android.OutputFileForModule(ctx, rustm, "") androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm) } From 553a31be9d357d9e7f90b0a1760791bf173add07 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 3 Oct 2022 22:02:09 -0700 Subject: [PATCH 5/6] Support AllowMissingDependencies in prebuilt_apex modules Arch-specfic prebuilt_apex modules may be missing prebuilts for new architectures. Mark the module as missing dependencies and allow build analysis to continue when AllowMissingDependencies is set. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Change-Id: I79f0c20a0c9443fe443f9ed9bc846aa649f6b6a6 --- apex/prebuilt.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apex/prebuilt.go b/apex/prebuilt.go index 25ae5bf7c..0f57911c6 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -537,7 +537,11 @@ func (p *ApexFileProperties) prebuiltApexSelector(ctx android.BaseModuleContext, } if src == "" { - ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String()) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{ctx.OtherModuleName(prebuilt)}) + } else { + ctx.OtherModuleErrorf(prebuilt, "prebuilt_apex does not support %q", multiTargets[0].Arch.String()) + } // Drop through to return an empty string as the src (instead of nil) to avoid the prebuilt // logic from reporting a more general, less useful message. } From 31d89b4e0cf22ea11b02c5c937c4c96c621cf819 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 4 Oct 2022 16:35:39 -0700 Subject: [PATCH 6/6] Move fuzzer's CollectAllSharedDependencies into GenerateAndroidBuildActions Make rust and cc fuzzers collect their shared libraries once in GenerateAndroidBuildActions and store it for later use by the packaging singleton. Also use android.OutputFileForModule to get the paths. Together this will fix fuzzers that depend on architecture specific prebuilt shared libraries that are missing a prebuilt for an architecture when building with AllowMissingDependencies. Bug: 250918230 Test: lunch aosp_riscv64-userdebug && m ALLOW_MISSING_DEPENDENCIES=true nothing Change-Id: I154a6f3a767c883e9fe7067003615db73ee78e2d --- cc/cc.go | 5 +++ cc/fuzz.go | 75 +++++++++++++++++++++++++++++---------------- fuzz/fuzz_common.go | 39 ----------------------- rust/fuzz.go | 15 ++++++--- 4 files changed, 64 insertions(+), 70 deletions(-) diff --git a/cc/cc.go b/cc/cc.go index 1c845f622..486295b7d 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -3330,6 +3330,11 @@ func (c *Module) OutputFiles(tag string) (android.Paths, error) { return android.Paths{c.outputFile.Path()}, nil } return android.Paths{}, nil + case "unstripped": + if c.linker != nil { + return android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), nil + } + return nil, nil default: return nil, fmt.Errorf("unsupported module reference tag %q", tag) } diff --git a/cc/fuzz.go b/cc/fuzz.go index 8a8c10723..13c94adb3 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -103,6 +103,7 @@ type fuzzBinary struct { *baseCompiler fuzzPackagedModule fuzz.FuzzPackagedModule installedSharedDeps []string + sharedLibraries android.Paths } func (fuzz *fuzzBinary) fuzzBinary() bool { @@ -142,13 +143,6 @@ func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func UnstrippedOutputFile(module android.Module) android.Path { - if mod, ok := module.(LinkableInterface); ok { - return mod.UnstrippedOutputFile() - } - panic("UnstrippedOutputFile called on non-LinkableInterface module: " + module.Name()) -} - // 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 // returns true, unless: @@ -270,22 +264,9 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { } // Grab the list of required shared libraries. - seen := make(map[string]bool) - var sharedLibraries android.Paths - ctx.WalkDeps(func(child, parent android.Module) bool { - if seen[child.Name()] { - return false - } - seen[child.Name()] = true + fuzzBin.sharedLibraries = CollectAllSharedDependencies(ctx) - if IsValidSharedDependency(child) { - sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile()) - return true - } - return false - }) - - for _, lib := range sharedLibraries { + for _, lib := range fuzzBin.sharedLibraries { fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, sharedLibraryInstallLocation( lib, ctx.Host(), installBase, ctx.Arch().ArchType.String())) @@ -412,9 +393,6 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} - // Grab the list of required shared libraries. - sharedLibraries := fuzz.CollectAllSharedDependencies(ctx, module, UnstrippedOutputFile, IsValidSharedDependency) - var files []fuzz.FileToZip builder := android.NewRuleBuilder(pctx, ctx) @@ -422,10 +400,10 @@ func (s *ccFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { files = s.PackageArtifacts(ctx, module, fpm, archDir, builder) // Package shared libraries - files = append(files, GetSharedLibsToZip(sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) + files = append(files, GetSharedLibsToZip(fuzzModule.sharedLibraries, ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) // The executable. - files = append(files, fuzz.FileToZip{ccModule.UnstrippedOutputFile(), ""}) + files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""}) archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok { @@ -494,3 +472,46 @@ func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, } return files } + +// CollectAllSharedDependencies search over the provided module's dependencies using +// VisitDirectDeps and WalkDeps to enumerate all shared library dependencies. +// VisitDirectDeps is used first to avoid incorrectly using 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.ModuleContext) android.Paths { + seen := make(map[string]bool) + recursed := make(map[string]bool) + + var sharedLibraries android.Paths + + // Enumerate the first level of dependencies, as we discard all non-library + // modules in the BFS loop below. + ctx.VisitDirectDeps(func(dep android.Module) { + if !IsValidSharedDependency(dep) { + return + } + if seen[ctx.OtherModuleName(dep)] { + return + } + seen[ctx.OtherModuleName(dep)] = true + sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped")) + }) + + ctx.WalkDeps(func(child, parent android.Module) bool { + if !IsValidSharedDependency(child) { + return false + } + if !seen[ctx.OtherModuleName(child)] { + seen[ctx.OtherModuleName(child)] = true + sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped")) + } + + if recursed[ctx.OtherModuleName(child)] { + return false + } + recursed[ctx.OtherModuleName(child)] = true + return true + }) + + return sharedLibraries +} diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index c8cd21b7e..eb248bb40 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -379,42 +379,3 @@ func (s *FuzzPackager) PreallocateSlice(ctx android.MakeVarsContext, targets str sort.Strings(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 -} diff --git a/rust/fuzz.go b/rust/fuzz.go index 586095c49..76cf21aa0 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -34,6 +34,7 @@ type fuzzDecorator struct { *binaryDecorator fuzzPackagedModule fuzz.FuzzPackagedModule + sharedLibraries android.Paths } var _ compiler = (*fuzzDecorator)(nil) @@ -86,6 +87,15 @@ func (fuzzer *fuzzDecorator) compilerProps() []interface{} { &fuzzer.fuzzPackagedModule.FuzzProperties) } +func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { + out := fuzzer.binaryDecorator.compile(ctx, flags, deps) + + // Grab the list of required shared libraries. + fuzzer.sharedLibraries = cc.CollectAllSharedDependencies(ctx) + + return out +} + func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage { return RlibLinkage } @@ -149,11 +159,8 @@ func (s *rustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { // The executable. files = append(files, fuzz.FileToZip{rustModule.UnstrippedOutputFile(), ""}) - // 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, "lib", &sharedLibraryInstalled)...) + files = append(files, cc.GetSharedLibsToZip(fuzzModule.sharedLibraries, rustModule, &s.FuzzPackager, archString, "lib", &sharedLibraryInstalled)...) archDirs[archOs], ok = s.BuildZipFile(ctx, module, fuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs) if !ok {