Skip to content

Commit

Permalink
Integration of pw_fuzzer using FuzzTest (#34274)
Browse files Browse the repository at this point in the history
* latest trial to build pw_fuzz

* migrating FuzzPayloadDecoder FuzzTest

* fix error related to latomic

* adding template for pw_fuzz_tests

* fix for linux_sysroot issue

* adding FuzzTests

* fixing warning issue

* adding support to build pw-fuzztests with build_examples.py

* Restyled by whitespace

* Restyled by clang-format

* adding pw_fuzz_tests to default target

* fixing build_examples test golden standard

* Adding Fuzzing Targets

* Adding Documentation

* cleaning-up tests

* spelling mistakes

* integrating comments

---------

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
2 people authored and pull[bot] committed Oct 3, 2024
1 parent 4cc3497 commit 49bdda0
Show file tree
Hide file tree
Showing 24 changed files with 824 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ AdvSendAdvert
AE
aef
AES
AFL
AIDL
algs
alloc
Expand Down Expand Up @@ -570,6 +571,7 @@ fsync
ftd
fullclean
fuzzer
fuzztest
FW
gbl
gcloud
Expand Down Expand Up @@ -1008,6 +1010,7 @@ optionOverride
optionsMask
optionsOverride
orgs
OSS
OTA
OTADownloader
otaDownloadPath
Expand Down
16 changes: 16 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,19 @@
path = third_party/infineon/psoc6/psoc6_sdk/libs/lwip-network-interface-integration
url = https://github.com/Infineon/lwip-network-interface-integration.git
platforms = infineon
[submodule "third_party/abseil-cpp/src"]
path = third_party/abseil-cpp/src
url = https://github.com/abseil/abseil-cpp.git
platforms = linux,darwin
[submodule "third_party/fuzztest"]
path = third_party/fuzztest
url = https://github.com/google/fuzztest.git
platforms = linux,darwin
[submodule "third_party/googletest"]
path = third_party/googletest
url = https://github.com/google/googletest
platforms = linux,darwin
[submodule "third_party/re2/src"]
path = third_party/re2/src
url = https://github.com/google/re2.git
platforms = linux,darwin
16 changes: 16 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
}
}

if (pw_enable_fuzz_test_targets) {
group("pw_fuzz_tests") {
deps = [
"${chip_root}/src/credentials/tests:fuzz-chip-cert-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
"${chip_root}/src/lib/core/tests:fuzz-tlv-reader-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
"${chip_root}/src/lib/dnssd/minimal_mdns/tests:fuzz-minmdns-packet-parsing-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
"${chip_root}/src/lib/format/tests:fuzz-payload-decoder-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
"${chip_root}/src/setup_payload/tests:fuzz-setup-payload-base38-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
]
}
}

# Matter's in-tree pw_python_package or pw_python_distribution targets.
_matter_python_packages = [
"//examples/chef",
Expand Down Expand Up @@ -140,6 +152,10 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
deps += [ "//:fuzz_tests" ]
}

if (pw_enable_fuzz_test_targets) {
deps += [ "//:pw_fuzz_tests" ]
}

if (chip_device_platform != "none") {
deps += [ "${chip_root}/src/app/server" ]
}
Expand Down
59 changes: 59 additions & 0 deletions build/chip/fuzz_test.gni
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@

import("//build_overrides/build.gni")
import("//build_overrides/chip.gni")
import("//build_overrides/pigweed.gni")

import("${build_root}/config/compiler/compiler.gni")
import("${chip_root}/build/chip/tests.gni")
import("${dir_pw_unit_test}/test.gni")

declare_args() {
enable_fuzz_test_targets = is_clang && chip_build_tests &&
(current_os == "linux" || current_os == "mac")

pw_enable_fuzz_test_targets = false
}

# Define a fuzz target for chip.
Expand Down Expand Up @@ -66,3 +71,57 @@ template("chip_fuzz_target") {
}
}
}

# Define a fuzz target for Matter using pw_fuzzer and Google FuzzTest Framework.
#
# Google FuzzTest is only supported on Linux and MacOS using Clang:
#
# Sample usage
#
# chip_pw_fuzz_target("fuzz-target-name") {
# test_source = [
# "FuzzTarget.cpp", # Fuzz target
# ]
#
# public_deps = [
# "${chip_root}/src/lib/foo", # add dependencies here
# ]
# }
#
#
template("chip_pw_fuzz_target") {
if (defined(invoker.test_source)) {
_test_output_dir = "${root_out_dir}/tests"

if (defined(invoker.output_dir)) {
_test_output_dir = invoker.output_dir
}

pw_test(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"cflags",
"configs",
"remove_configs",
])

# TODO: remove this after pw_fuzzer's integration with OSS-Fuzz is complete.
#just a test for running FuzzTest with libfuzzer-compatibility mode, since this is the mode supported by OSS-fuzz
# defines = [
# "FUZZTEST_COMPATIBILITY_MODE=libfuzzer",
# "MAKE_BUILD_TYPE=RelWithDebug",
# ]

sources = invoker.test_source
output_dir = _test_output_dir

deps = [ "$dir_pw_fuzzer:fuzztest" ]

# this is necessary so FuzzTest is compiled into an executable in third_party/pigweed/repo/pw_unit_test/test.gni
# otherwise it will be built successfully but with FuzzTarget.DISABLED.ninja and no executable.
enable_if = true
}
}
}
70 changes: 70 additions & 0 deletions build/toolchain/pw_fuzzer/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Copyright (c) 2024 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import("//build_overrides/build.gni")
import("//build_overrides/pigweed.gni")

import("$dir_pigweed/targets/host/target_toolchains.gni")
import("${build_root}/toolchain/gcc_toolchain.gni")

# creating a secondary toolchain to be used with pw_fuzzer FuzzTests
# This toolchain is downstreamed from pigweed's pw_target_toolchain_host.clang_fuzz
# it allows us to specifically use googletest for fuzzing (instead of the lighter version of googletest used for unit testing)

gcc_toolchain("chip_pw_fuzztest") {
forward_variables_from(pw_target_toolchain_host.clang_fuzz, "*", [ "name" ])

toolchain_args = {
# This is needed to have the defaults passed from pw_target_toolchain_host.clang_fuzz to the current scope
forward_variables_from(defaults, "*")

pw_unit_test_MAIN = "$dir_pw_fuzzer:fuzztest_main"
pw_unit_test_BACKEND = "$dir_pw_fuzzer:gtest"

# The next three lines are needed by the gcc_toolchain template
current_os = host_os
current_cpu = host_cpu
is_clang = true

# the upstream pigweed host_clang toolchain defines a default sysroot, which results in build errors
# since it does not include SSL lib and is supposed to be minimal by design.
# by removing this default config, we will use the system's libs. Otherwise we can define our own sysroot.
# discussion on: https://discord.com/channels/691686718377558037/1275092695764959232
remove_default_configs = [ "$dir_pw_toolchain/host_clang:linux_sysroot" ]

# when is_debug = true, we pass -O0 to cflags and ldflags, while upstream pw_fuzzer toolchain defines "optimize_speed" config that passes -O2.
# This condition was added to prevent mixing the flags
if (is_debug) {
remove_default_configs += [ "$dir_pw_build:optimize_speed" ]
}

# removing pigweed downstreamed configs related to warnings
# These are triggering an error related to -Wcast-qual in third_party/nlio
remove_default_configs += [
"$dir_pw_build:strict_warnings",
"$dir_pw_build:extra_strict_warnings",
]

# the third_party abseil-cpp triggers warnings related to [-Wformat-nonliteral]
treat_warnings_as_errors = false

dir_pw_third_party_abseil_cpp = "//third_party/abseil-cpp/src"
dir_pw_third_party_fuzztest = "//third_party/fuzztest"
dir_pw_third_party_googletest = "//third_party/googletest"

# TODO: Seems that re2 support within FuzzTest was deprecated, keeping it defined is triggering warning
# Remove if re2 is indeed not needed
# dir_pw_third_party_re2 = "//third_party/re2/src"
}
}
20 changes: 20 additions & 0 deletions docs/guides/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,26 @@ They pick up environment variables such as `$CFLAGS`, `$CXXFLAGS` and
You likely want `libfuzzer` + `asan` builds instead for local testing.
### `pw_fuzzer` `FuzzTests`
An Alternative way for writing and running Fuzz Tests is Google's `FuzzTest`
framework, integrated through `pw_fuzzer`. The Tests will have to be built and
executed manually.
```
./scripts/build/build_examples.py --target linux-x64-tests-clang-pw-fuzztest build
```
NOTE: `asan` is enabled by default in FuzzTest, so please do not add it in
build_examples.py invocation.
Tests will be located in:
`out/linux-x64-tests-clang-pw-fuzztest/chip_pw_fuzztest/tests/` where
`chip_pw_fuzztest` is the name of the toolchain used.
- Details on How To Run Fuzz Tests in
[Running FuzzTests](https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/fuzz_testing.md)
## Build custom configuration
The build is configured by setting build arguments. These you can set in one of
Expand Down
Loading

0 comments on commit 49bdda0

Please sign in to comment.