Revert^2 "Update the way we build AFL++ fuzz binaries"

Test: Built AFL fuzzers individually and built all using haiku command
and built libfuzzers individually and also by using haiku command. Ran
selected fuzzers manually to ensure fuzzing still worked.

Description: Previously we needed to add cc_afl_fuzz to build an afl fuzz binary,
however, to turn current libFuzzers into AFL fuzzers this would required
an update to each Android.bp file which is a lot of work, and would also
require an approval from each Android.bp file owner, which is even more
work.

To get around this (and also to match how AFL fuzzers are built in G3)
we will build AFL++ fuzz binaries by command line option FUZZ_FRAMEWORK.
When FUZZ_FRAMEWORK=AFL is set, all cc_fuzz modules will be built
for AFL rather than libFuzzer. Devs can also specify if a cc_fuzz module
is only for libFuzzer or AFL by using fuzzing_frameworks. If
fuzzing_frameworks is left blank then it will be assumed that the
cc_fuzz module can be built for all available fuzzing frameworks.

Change-Id: If57d3038f05e52775177eaeb26f8ed2bdc73443a
diff --git a/cc/cc.go b/cc/cc.go
index bc95813..fd57e9e 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -62,7 +62,6 @@
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
 		ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
-		ctx.BottomUp("fuzz", fuzzMutator)
 
 		ctx.BottomUp("coverage", coverageMutator).Parallel()
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 24732bf..792a8e0 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"reflect"
 	"regexp"
+	"runtime"
 	"strings"
 	"testing"
 
@@ -3342,9 +3343,9 @@
 	`)
 }
 
-func TestAFLFuzzTarget(t *testing.T) {
-	ctx := testCc(t, `
-		cc_afl_fuzz {
+func VerifyAFLFuzzTargetVariant(t *testing.T, variant string) {
+	bp := `
+		cc_fuzz {
 			name: "test_afl_fuzz_target",
 			srcs: ["foo.c"],
 			host_supported: true,
@@ -3354,17 +3355,10 @@
 			shared_libs: [
 				"afl_fuzz_shared_lib",
 			],
-		}
-		cc_fuzz {
-			name: "test_fuzz_target",
-			srcs: ["foo.c"],
-			static_libs: [
-				"afl_fuzz_static_lib",
-				"libfuzzer_only_static_lib",
-			],
-			shared_libs: [
-				"afl_fuzz_shared_lib",
-			],
+			fuzzing_frameworks: {
+				afl: true,
+				libfuzzer: false,
+			},
 		}
 		cc_library {
 			name: "afl_fuzz_static_lib",
@@ -3409,12 +3403,19 @@
 			host_supported: true,
 			srcs: ["second_file.c"],
 		}
-		filegroup {
+		cc_object {
 			name: "aflpp_driver",
+			host_supported: true,
 			srcs: [
 				"aflpp_driver.c",
 			],
-		}`)
+		}`
+
+	testEnv := map[string]string{
+		"FUZZ_FRAMEWORK": "AFL",
+	}
+
+	ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)
 
 	checkPcGuardFlag := func(
 		modName string, variantName string, shouldHave bool) {
@@ -3434,31 +3435,33 @@
 		}
 	}
 
-	for _, vnt := range ctx.ModuleVariantsForTests("libfuzzer_only_static_lib") {
-		if strings.Contains(vnt, "fuzzer_afl") {
-			t.Errorf("libfuzzer_only_static_lib has afl variant and should not")
-		}
-	}
-
 	moduleName := "test_afl_fuzz_target"
-	variantName := "android_arm64_armv8-a_fuzzer_afl"
-	checkPcGuardFlag(moduleName, variantName, true)
+	checkPcGuardFlag(moduleName, variant+"_fuzzer", true)
 
 	moduleName = "afl_fuzz_static_lib"
-	variantName = "android_arm64_armv8-a_static"
-	checkPcGuardFlag(moduleName, variantName, false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
+	checkPcGuardFlag(moduleName, variant+"_static", false)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
 
 	moduleName = "second_static_lib"
-	checkPcGuardFlag(moduleName, variantName, false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer", false)
-	checkPcGuardFlag(moduleName, variantName+"_fuzzer_afl", true)
+	checkPcGuardFlag(moduleName, variant+"_static", false)
+	checkPcGuardFlag(moduleName, variant+"_static_fuzzer", true)
 
 	ctx.ModuleForTests("afl_fuzz_shared_lib",
 		"android_arm64_armv8-a_shared").Rule("cc")
 	ctx.ModuleForTests("afl_fuzz_shared_lib",
-		"android_arm64_armv8-a_shared_fuzzer_afl").Rule("cc")
+		"android_arm64_armv8-a_shared_fuzzer").Rule("cc")
+}
+
+func TestAFLFuzzTargetForDevice(t *testing.T) {
+	VerifyAFLFuzzTargetVariant(t, "android_arm64_armv8-a")
+}
+
+func TestAFLFuzzTargetForLinuxHost(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	VerifyAFLFuzzTargetVariant(t, "linux_glibc_x86_64")
 }
 
 // Simple smoke test for the cc_fuzz target that ensures the rule compiles
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d6af97f..dfc718e 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -27,15 +27,12 @@
 )
 
 func init() {
-	android.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 	android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
 	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
-	android.RegisterSingletonType("cc_afl_fuzz_packaging", fuzzAFLPackagingFactory)
 }
 
 type FuzzProperties struct {
-	AFLEnabled  bool `blueprint:"mutated"`
-	AFLAddFlags bool `blueprint:"mutated"`
+	FuzzFramework fuzz.Framework `blueprint:"mutated"`
 }
 
 type fuzzer struct {
@@ -43,8 +40,13 @@
 }
 
 func (fuzzer *fuzzer) flags(ctx ModuleContext, flags Flags) Flags {
-	if fuzzer.Properties.AFLAddFlags {
-		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-coverage=trace-pc-guard")
+	if fuzzer.Properties.FuzzFramework == fuzz.AFL {
+		flags.Local.CFlags = append(flags.Local.CFlags, []string{
+			"-fsanitize-coverage=trace-pc-guard",
+			"-Wno-unused-result",
+			"-Wno-unused-parameter",
+			"-Wno-unused-function",
+		}...)
 	}
 
 	return flags
@@ -60,7 +62,7 @@
 		return
 	}
 
-	if currentModule.fuzzer == nil || !currentModule.fuzzer.Properties.AFLEnabled {
+	if currentModule.fuzzer == nil {
 		return
 	}
 
@@ -83,48 +85,16 @@
 			return false
 		}
 
-		c.fuzzer.Properties.AFLEnabled = true
-		c.fuzzer.Properties.AFLAddFlags = true
+		c.fuzzer.Properties.FuzzFramework = currentModule.fuzzer.Properties.FuzzFramework
 		return true
 	})
 }
 
-func fuzzMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.fuzzer != nil {
-		if !c.fuzzer.Properties.AFLEnabled {
-			return
-		}
-
-		if c.Binary() {
-			m := mctx.CreateVariations("afl")
-			m[0].(*Module).fuzzer.Properties.AFLEnabled = true
-			m[0].(*Module).fuzzer.Properties.AFLAddFlags = true
-		} else {
-			m := mctx.CreateVariations("", "afl")
-			m[0].(*Module).fuzzer.Properties.AFLEnabled = false
-			m[0].(*Module).fuzzer.Properties.AFLAddFlags = false
-
-			m[1].(*Module).fuzzer.Properties.AFLEnabled = true
-			m[1].(*Module).fuzzer.Properties.AFLAddFlags = true
-		}
-	}
-}
-
 // cc_fuzz creates a host/device fuzzer binary. Host binaries can be found at
 // $ANDROID_HOST_OUT/fuzz/, and device binaries can be found at /data/fuzz on
 // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
 func LibFuzzFactory() android.Module {
-	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.Cc)
-	return module.Init()
-}
-
-// cc_afl_fuzz creates a host/device AFL++ fuzzer binary.
-// AFL++ is an open source framework used to fuzz libraries
-// Host binaries can be found at $ANDROID_HOST_OUT/afl_fuzz/ and device
-// binaries can be found at $ANDROID_PRODUCT_OUT/data/afl_fuzz in your
-// build tree
-func AFLFuzzFactory() android.Module {
-	module := NewFuzzer(android.HostAndDeviceSupported, fuzz.AFL)
+	module := NewFuzzer(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
@@ -133,7 +103,6 @@
 	*baseCompiler
 	fuzzPackagedModule  fuzz.FuzzPackagedModule
 	installedSharedDeps []string
-	fuzzType            fuzz.FuzzType
 }
 
 func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -143,6 +112,7 @@
 func (fuzz *fuzzBinary) linkerProps() []interface{} {
 	props := fuzz.binaryDecorator.linkerProps()
 	props = append(props, &fuzz.fuzzPackagedModule.FuzzProperties)
+
 	return props
 }
 
@@ -151,16 +121,14 @@
 }
 
 func (fuzzBin *fuzzBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
-	if fuzzBin.fuzzType == fuzz.AFL {
+	if ctx.Config().Getenv("FUZZ_FRAMEWORK") == "AFL" {
 		deps.HeaderLibs = append(deps.HeaderLibs, "libafl_headers")
-		deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
-		return deps
-
 	} else {
 		deps.StaticLibs = append(deps.StaticLibs, config.LibFuzzerRuntimeLibrary(ctx.toolchain()))
-		deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
-		return deps
 	}
+
+	deps = fuzzBin.binaryDecorator.linkerDeps(ctx, deps)
+	return deps
 }
 
 func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
@@ -257,9 +225,6 @@
 
 func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
 	installBase := "fuzz"
-	if fuzzBin.fuzzType == fuzz.AFL {
-		installBase = "afl_fuzz"
-	}
 
 	fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
 		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -333,12 +298,9 @@
 	}
 }
 
-func NewFuzzer(hod android.HostOrDeviceSupported, fuzzType fuzz.FuzzType) *Module {
+func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
 	module, binary := newBinary(hod, false)
 	baseInstallerPath := "fuzz"
-	if fuzzType == fuzz.AFL {
-		baseInstallerPath = "afl_fuzz"
-	}
 
 	binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
 	module.sanitize.SetSanitizer(Fuzzer, true)
@@ -346,12 +308,13 @@
 	fuzzBin := &fuzzBinary{
 		binaryDecorator: binary,
 		baseCompiler:    NewBaseCompiler(),
-		fuzzType:        fuzzType,
 	}
 	module.compiler = fuzzBin
 	module.linker = fuzzBin
 	module.installer = fuzzBin
 
+	module.fuzzer.Properties.FuzzFramework = fuzz.LibFuzzer
+
 	// The fuzzer runtime is not present for darwin host modules, disable cc_fuzz modules when targeting darwin.
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
 		disableDarwinAndLinuxBionic := struct {
@@ -367,18 +330,18 @@
 		disableDarwinAndLinuxBionic.Target.Darwin.Enabled = BoolPtr(false)
 		disableDarwinAndLinuxBionic.Target.Linux_bionic.Enabled = BoolPtr(false)
 		ctx.AppendProperties(&disableDarwinAndLinuxBionic)
-	})
 
-	if fuzzType == fuzz.AFL {
-		// Add cc_objects to Srcs
-		fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
-		module.fuzzer.Properties.AFLEnabled = true
-		module.compiler.appendCflags([]string{
-			"-Wno-unused-result",
-			"-Wno-unused-parameter",
-			"-Wno-unused-function",
-		})
-	}
+		targetFramework := fuzz.GetFramework(ctx, fuzz.Cc)
+		if !fuzz.IsValidFrameworkForModule(targetFramework, fuzz.Cc, fuzzBin.fuzzPackagedModule.FuzzProperties.Fuzzing_frameworks) {
+			ctx.Module().Disable()
+			return
+		}
+
+		if targetFramework == fuzz.AFL {
+			fuzzBin.baseCompiler.Properties.Srcs = append(fuzzBin.baseCompiler.Properties.Srcs, ":aflpp_driver", ":afl-compiler-rt")
+			module.fuzzer.Properties.FuzzFramework = fuzz.AFL
+		}
+	})
 
 	return module
 }
@@ -399,17 +362,6 @@
 		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
 	}
-	fuzzPackager.FuzzType = fuzz.Cc
-	return fuzzPackager
-}
-
-func fuzzAFLPackagingFactory() android.Singleton {
-	fuzzPackager := &ccFuzzPackager{
-		fuzzPackagingArchModules:         "SOONG_AFL_FUZZ_PACKAGING_ARCH_MODULES",
-		fuzzTargetSharedDepsInstallPairs: "AFL_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
-		allFuzzTargetsName:               "ALL_AFL_FUZZ_TARGETS",
-	}
-	fuzzPackager.FuzzType = fuzz.AFL
 	return fuzzPackager
 }
 
@@ -440,7 +392,7 @@
 
 		sharedLibsInstallDirPrefix := "lib"
 		fuzzModule, ok := ccModule.compiler.(*fuzzBinary)
-		if !ok || fuzzModule.fuzzType != s.FuzzType {
+		if !ok {
 			return
 		}
 
@@ -455,9 +407,6 @@
 		}
 
 		intermediatePath := "fuzz"
-		if s.FuzzType == fuzz.AFL {
-			intermediatePath = "afl_fuzz"
-		}
 
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, intermediatePath, hostOrTargetString, archString)
@@ -484,7 +433,7 @@
 		}
 	})
 
-	s.CreateFuzzPackage(ctx, archDirs, s.FuzzType, pctx)
+	s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx)
 }
 
 func (s *ccFuzzPackager) MakeVars(ctx android.MakeVarsContext) {
@@ -511,9 +460,6 @@
 	var files []fuzz.FileToZip
 
 	fuzzDir := "fuzz"
-	if s.FuzzType == fuzz.AFL {
-		fuzzDir = "afl_fuzz"
-	}
 
 	for _, library := range sharedLibraries {
 		files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
diff --git a/cc/testing.go b/cc/testing.go
index d70ec9b..79ae3c3 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -531,7 +531,6 @@
 	android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest),
 	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 		ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
-		ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 		ctx.RegisterModuleType("cc_test", TestFactory)
 		ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
 		ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
@@ -646,7 +645,6 @@
 	ctx := android.NewTestArchContext(config)
 	genrule.RegisterGenruleBuildComponents(ctx)
 	ctx.RegisterModuleType("cc_fuzz", LibFuzzFactory)
-	ctx.RegisterModuleType("cc_afl_fuzz", AFLFuzzFactory)
 	ctx.RegisterModuleType("cc_test", TestFactory)
 	ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 2474cbc..c8cd21b 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -27,13 +27,21 @@
 	"android/soong/android"
 )
 
-type FuzzType string
+type Lang string
 
 const (
-	Cc   FuzzType = ""
-	Rust FuzzType = "rust"
-	Java FuzzType = "java"
-	AFL  FuzzType = "AFL"
+	Cc   Lang = "cc"
+	Rust Lang = "rust"
+	Java Lang = "java"
+)
+
+type Framework string
+
+const (
+	AFL              Framework = "afl"
+	LibFuzzer        Framework = "libfuzzer"
+	Jazzer           Framework = "jazzer"
+	UnknownFramework Framework = "unknownframework"
 )
 
 var BoolDefault = proptools.BoolDefault
@@ -48,7 +56,6 @@
 	Packages                android.Paths
 	FuzzTargets             map[string]bool
 	SharedLibInstallStrings []string
-	FuzzType                FuzzType
 }
 
 type FileToZip struct {
@@ -146,6 +153,12 @@
 	IsJni *bool `json:"is_jni,omitempty"`
 }
 
+type FuzzFrameworks struct {
+	Afl       *bool
+	Libfuzzer *bool
+	Jazzer    *bool
+}
+
 type FuzzProperties struct {
 	// Optional list of seed files to be installed to the fuzz target's output
 	// directory.
@@ -155,6 +168,10 @@
 	Data []string `android:"path"`
 	// Optional dictionary to be installed to the fuzz target's output directory.
 	Dictionary *string `android:"path"`
+	// Define the fuzzing frameworks this fuzz target can be built for. If
+	// empty then the fuzz target will be available to be  built for all fuzz
+	// frameworks available
+	Fuzzing_frameworks *FuzzFrameworks
 	// Config for running the target on fuzzing infrastructure.
 	Fuzz_config *FuzzConfig
 }
@@ -169,6 +186,49 @@
 	DataIntermediateDir   android.Path
 }
 
+func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
+	framework := ctx.Config().Getenv("FUZZ_FRAMEWORK")
+
+	if lang == Cc {
+		switch strings.ToLower(framework) {
+		case "":
+			return LibFuzzer
+		case "libfuzzer":
+			return LibFuzzer
+		case "afl":
+			return AFL
+		}
+	} else if lang == Rust {
+		return LibFuzzer
+	} else if lang == Java {
+		return Jazzer
+	}
+
+	ctx.ModuleErrorf(fmt.Sprintf("%s is not a valid fuzzing framework for %s", framework, lang))
+	return UnknownFramework
+}
+
+func IsValidFrameworkForModule(targetFramework Framework, lang Lang, moduleFrameworks *FuzzFrameworks) bool {
+	if targetFramework == UnknownFramework {
+		return false
+	}
+
+	if moduleFrameworks == nil {
+		return true
+	}
+
+	switch targetFramework {
+	case LibFuzzer:
+		return proptools.BoolDefault(moduleFrameworks.Libfuzzer, true)
+	case AFL:
+		return proptools.BoolDefault(moduleFrameworks.Afl, true)
+	case Jazzer:
+		return proptools.BoolDefault(moduleFrameworks.Jazzer, true)
+	default:
+		panic("%s is not supported as a fuzz framework")
+	}
+}
+
 func IsValid(fuzzModule FuzzModule) bool {
 	// Discard ramdisk + vendor_ramdisk + recovery modules, they're duplicates of
 	// fuzz targets we're going to package anyway.
@@ -267,7 +327,7 @@
 	return string(b)
 }
 
-func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType FuzzType, pctx android.PackageContext) {
+func (s *FuzzPackager) CreateFuzzPackage(ctx android.SingletonContext, archDirs map[ArchOs][]FileToZip, fuzzType Lang, pctx android.PackageContext) {
 	var archOsList []ArchOs
 	for archOs := range archDirs {
 		archOsList = append(archOsList, archOs)
@@ -286,9 +346,7 @@
 		if fuzzType == Java {
 			zipFileName = "fuzz-java-" + hostOrTarget + "-" + arch + ".zip"
 		}
-		if fuzzType == AFL {
-			zipFileName = "fuzz-afl-" + hostOrTarget + "-" + arch + ".zip"
-		}
+
 		outputFile := android.PathForOutput(ctx, zipFileName)
 
 		s.Packages = append(s.Packages, outputFile)