diff --git a/build/fuzzing/fuzzer.gni b/build/fuzzing/fuzzer.gni index 9049b53dfea14b944124c81ccbc83b6441174ba6..ac30e113e4316716b44e5f4d489f219dd26c9cb2 100644 --- a/build/fuzzing/fuzzer.gni +++ b/build/fuzzing/fuzzer.gni @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/host.gni") import("//build/package.gni") # TODO(aarongreen): SEC-224. Add tests to catch fuzzer building/packaging @@ -204,9 +205,16 @@ template("fuzz_package") { ] } + if (defined(invoker.fuzz_host)) { + fuzz_host = invoker.fuzz_host + } else { + fuzz_host = false + } + # Collect the selected fuzz targets listed in this package based on the # variants selected in args.gn and filtered by the package's list of # supported sanitizers. + selected = false selected_targets = [] foreach(fuzz_target, invoker.targets) { selected = false @@ -223,9 +231,6 @@ template("fuzz_package") { } } } - - # When no variants are present, `selected` is unused. - not_needed([ "selected" ]) } # Assemble the Fuchsia package @@ -239,12 +244,14 @@ template("fuzz_package") { foreach(selected_target, selected_targets) { fuzz_targets += [ get_label_info(selected_target, "name") ] } + fuzz_host = fuzz_host }, ] if (defined(invoker.metadata)) { forward_variables_from(invoker.metadata, "*", [ "fuzz_spec" ]) } } + deps = [] components = [] forward_variables_from(invoker, [ "visibility" ]) forward_variables_from(invoker, @@ -259,19 +266,32 @@ template("fuzz_package") { foreach(selected_target, selected_targets) { components += [ "${selected_target}_component" ] } + if (fuzz_host) { + deps += [ ":host_${target_name}" ] + } + } + + # Treat host fuzzers as tools. If we get to the point of having name + # collisions, we'll need to extend `install_host_tools` to allow copying to + # specific subdirectories of `host_tools_dir` + if (fuzz_host) { + install_host_tools("host_${target_name}") { + testonly = true + deps = selected_targets + outputs = [] + foreach(target, selected_targets) { + outputs += [ get_label_info(target, "name") ] + } + } } } else { # Dummy package for non-fuzzed builds group(target_name) { } not_needed(invoker, "*") - } - - # Create a (possibly empty) target for host fuzzers - group("host_${target_name}") { - testonly = true - if (defined(invoker.fuzz_host) && invoker.fuzz_host) { - deps = selected_targets - } + not_needed([ + "fuzz_host", + "selected", + ]) } } diff --git a/garnet/packages/tests/BUILD.gn b/garnet/packages/tests/BUILD.gn index 1bfba83658ea9e562e5baba1b3c0182fb0d4a74f..33c46338a7e4ba4238a04b3ecb405289c134329f 100644 --- a/garnet/packages/tests/BUILD.gn +++ b/garnet/packages/tests/BUILD.gn @@ -578,7 +578,6 @@ group("overnet") { public_deps = [ # FIXME(FLK-187, FLK-188): Disabled because of flakes. # "//src/connectivity/overnet/examples:overnet_examples_tests", - "//src/connectivity/overnet/lib:host_overnet_fuzzers", "//src/connectivity/overnet/lib:overnet_fuzzers", "//src/connectivity/overnet/lib:overnet_tests", "//src/connectivity/overnet/lib:overnet_unittests($host_toolchain)", diff --git a/src/BUILD.gn b/src/BUILD.gn index 8ef3c9e28beca470fe43687296ae585e52add5ba..cc5503efcfef270659f368684a4af02e4515b605 100644 --- a/src/BUILD.gn +++ b/src/BUILD.gn @@ -29,6 +29,7 @@ group("tests") { "cobalt:tests", "connectivity:tests", "developer:tests", + "fuzzing:tests", "identity:tests", "ledger:tests", "lib:tests", diff --git a/src/fuzzing/BUILD.gn b/src/fuzzing/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e2c7b803428112421b7e0f97a7f6dfd53170ab56 --- /dev/null +++ b/src/fuzzing/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright 2019 The Fuchsia Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/go/go_library.gni") +import("//build/go/go_test.gni") + +group("tests") { + testonly = true + public_deps = [ + ":host_fuzzers_test($host_toolchain)", + ] +} + +go_library("host_fuzzers_test_lib") { + name = "fuzzing" +} + +go_test("host_fuzzers_test") { + gopackage = "fuzzing" + deps = [ + ":host_fuzzers_test_lib", + ] +} diff --git a/src/fuzzing/OWNERS b/src/fuzzing/OWNERS new file mode 100644 index 0000000000000000000000000000000000000000..4e1e62c26b879e3b2888540b45f06d01248ecba7 --- /dev/null +++ b/src/fuzzing/OWNERS @@ -0,0 +1,3 @@ +aarongreen@google.com +flowerhack@google.com +mvanotti@google.com diff --git a/src/fuzzing/host_test.go b/src/fuzzing/host_test.go new file mode 100644 index 0000000000000000000000000000000000000000..96e4e80c41120261dc45929e1928138b838e120d --- /dev/null +++ b/src/fuzzing/host_test.go @@ -0,0 +1,91 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package fuzzing + +import ( + "encoding/json" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "testing" +) + +// Created by `fuzz_package` in //build/fuzzing/fuzzer.gni +type FuzzSpec struct { + Host bool `json:"fuzz_host"` + Package string `json:"fuzz_package"` + Targets []string `json:"fuzz_targets"` +} + +func TestHostFuzzers(t *testing.T) { + // Search the build directory structure for host variant fuzzer builds. + // This is necessarily sensitive to the layout of the build directory and + // will need to be updated if the host tests are moved or the host fuzzer + // builds' names change. + testBin, err := os.Executable() + if err != nil { + t.Fatalf("Failed to determine executable path: %v", err) + } + fxBuildDir := path.Dir(path.Dir(testBin)) + + // Find the fuzzers that should have been built for host. + jsonPath := path.Join(fxBuildDir, "fuzzers.json") + _, err = os.Stat(jsonPath) + if err != nil && os.IsNotExist(err) { + t.SkipNow() + } + jsonFile, err := os.Open(jsonPath) + if err != nil { + t.Fatalf("Failed to find fuzzer.json: %v", err) + } + defer jsonFile.Close() + + jsonData, err := ioutil.ReadAll(jsonFile) + if err != nil { + t.Fatalf("Failed to read fuzzer.json: %v", err) + } + + var specs []FuzzSpec + err = json.Unmarshal(jsonData, &specs) + if err != nil { + t.Fatalf("Failed to parse fuzzer.json: %v", err) + } + fuzzers := []string{} + for _, spec := range specs { + if spec.Host { + fuzzers = append(fuzzers, spec.Targets...) + } + } + + // Create a empty file to act as a single input to each fuzzer. + variants, err := filepath.Glob(path.Join(fxBuildDir, "host_*-fuzzer")) + if err != nil { + t.Fatalf("Failed to glob host fuzzer build directories: %v", err) + } + if len(variants) == 0 { + t.SkipNow() + } + tempFile, err := ioutil.TempFile("", "empty.input") + if err != nil { + t.Fatalf("Failed to create empty input: %v", err) + } + tempName := tempFile.Name() + tempFile.Close() + defer os.Remove(tempName) + + // Check that each fuzzer runs and exits cleanly. + for _, variant := range variants { + for _, fuzzer := range fuzzers { + cmd := exec.Command(path.Join(variant, fuzzer), tempName) + output, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("Failed to run %s: %v", fuzzer, err) + } + t.Log(string(output[:])) + } + } +}