Skip to content

Commit 1e1fe1e

Browse files
Integration of pw_fuzzer using FuzzTest (#34274)
* 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>
1 parent 30cff8e commit 1e1fe1e

File tree

24 files changed

+824
-2
lines changed

24 files changed

+824
-2
lines changed

.github/.wordlist.txt

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ AdvSendAdvert
3737
AE
3838
aef
3939
AES
40+
AFL
4041
AIDL
4142
algs
4243
alloc
@@ -570,6 +571,7 @@ fsync
570571
ftd
571572
fullclean
572573
fuzzer
574+
fuzztest
573575
FW
574576
gbl
575577
gcloud
@@ -1008,6 +1010,7 @@ optionOverride
10081010
optionsMask
10091011
optionsOverride
10101012
orgs
1013+
OSS
10111014
OTA
10121015
OTADownloader
10131016
otaDownloadPath

.gitmodules

+16
Original file line numberDiff line numberDiff line change
@@ -329,3 +329,19 @@
329329
path = third_party/infineon/psoc6/psoc6_sdk/libs/lwip-network-interface-integration
330330
url = https://github.com/Infineon/lwip-network-interface-integration.git
331331
platforms = infineon
332+
[submodule "third_party/abseil-cpp/src"]
333+
path = third_party/abseil-cpp/src
334+
url = https://github.com/abseil/abseil-cpp.git
335+
platforms = linux,darwin
336+
[submodule "third_party/fuzztest"]
337+
path = third_party/fuzztest
338+
url = https://github.com/google/fuzztest.git
339+
platforms = linux,darwin
340+
[submodule "third_party/googletest"]
341+
path = third_party/googletest
342+
url = https://github.com/google/googletest
343+
platforms = linux,darwin
344+
[submodule "third_party/re2/src"]
345+
path = third_party/re2/src
346+
url = https://github.com/google/re2.git
347+
platforms = linux,darwin

BUILD.gn

+16
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
6262
}
6363
}
6464

65+
if (pw_enable_fuzz_test_targets) {
66+
group("pw_fuzz_tests") {
67+
deps = [
68+
"${chip_root}/src/credentials/tests:fuzz-chip-cert-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
69+
"${chip_root}/src/lib/core/tests:fuzz-tlv-reader-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
70+
"${chip_root}/src/lib/dnssd/minimal_mdns/tests:fuzz-minmdns-packet-parsing-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
71+
"${chip_root}/src/lib/format/tests:fuzz-payload-decoder-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
72+
"${chip_root}/src/setup_payload/tests:fuzz-setup-payload-base38-pw(//build/toolchain/pw_fuzzer:chip_pw_fuzztest)",
73+
]
74+
}
75+
}
76+
6577
# Matter's in-tree pw_python_package or pw_python_distribution targets.
6678
_matter_python_packages = [
6779
"//examples/chef",
@@ -140,6 +152,10 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") {
140152
deps += [ "//:fuzz_tests" ]
141153
}
142154

155+
if (pw_enable_fuzz_test_targets) {
156+
deps += [ "//:pw_fuzz_tests" ]
157+
}
158+
143159
if (chip_device_platform != "none") {
144160
deps += [ "${chip_root}/src/app/server" ]
145161
}

build/chip/fuzz_test.gni

+59
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@
1414

1515
import("//build_overrides/build.gni")
1616
import("//build_overrides/chip.gni")
17+
import("//build_overrides/pigweed.gni")
18+
1719
import("${build_root}/config/compiler/compiler.gni")
1820
import("${chip_root}/build/chip/tests.gni")
21+
import("${dir_pw_unit_test}/test.gni")
1922

2023
declare_args() {
2124
enable_fuzz_test_targets = is_clang && chip_build_tests &&
2225
(current_os == "linux" || current_os == "mac")
26+
27+
pw_enable_fuzz_test_targets = false
2328
}
2429

2530
# Define a fuzz target for chip.
@@ -66,3 +71,57 @@ template("chip_fuzz_target") {
6671
}
6772
}
6873
}
74+
75+
# Define a fuzz target for Matter using pw_fuzzer and Google FuzzTest Framework.
76+
#
77+
# Google FuzzTest is only supported on Linux and MacOS using Clang:
78+
#
79+
# Sample usage
80+
#
81+
# chip_pw_fuzz_target("fuzz-target-name") {
82+
# test_source = [
83+
# "FuzzTarget.cpp", # Fuzz target
84+
# ]
85+
#
86+
# public_deps = [
87+
# "${chip_root}/src/lib/foo", # add dependencies here
88+
# ]
89+
# }
90+
#
91+
#
92+
template("chip_pw_fuzz_target") {
93+
if (defined(invoker.test_source)) {
94+
_test_output_dir = "${root_out_dir}/tests"
95+
96+
if (defined(invoker.output_dir)) {
97+
_test_output_dir = invoker.output_dir
98+
}
99+
100+
pw_test(target_name) {
101+
forward_variables_from(invoker,
102+
[
103+
"deps",
104+
"public_deps",
105+
"cflags",
106+
"configs",
107+
"remove_configs",
108+
])
109+
110+
# TODO: remove this after pw_fuzzer's integration with OSS-Fuzz is complete.
111+
#just a test for running FuzzTest with libfuzzer-compatibility mode, since this is the mode supported by OSS-fuzz
112+
# defines = [
113+
# "FUZZTEST_COMPATIBILITY_MODE=libfuzzer",
114+
# "MAKE_BUILD_TYPE=RelWithDebug",
115+
# ]
116+
117+
sources = invoker.test_source
118+
output_dir = _test_output_dir
119+
120+
deps = [ "$dir_pw_fuzzer:fuzztest" ]
121+
122+
# this is necessary so FuzzTest is compiled into an executable in third_party/pigweed/repo/pw_unit_test/test.gni
123+
# otherwise it will be built successfully but with FuzzTarget.DISABLED.ninja and no executable.
124+
enable_if = true
125+
}
126+
}
127+
}

build/toolchain/pw_fuzzer/BUILD.gn

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright (c) 2024 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("//build_overrides/build.gni")
16+
import("//build_overrides/pigweed.gni")
17+
18+
import("$dir_pigweed/targets/host/target_toolchains.gni")
19+
import("${build_root}/toolchain/gcc_toolchain.gni")
20+
21+
# creating a secondary toolchain to be used with pw_fuzzer FuzzTests
22+
# This toolchain is downstreamed from pigweed's pw_target_toolchain_host.clang_fuzz
23+
# it allows us to specifically use googletest for fuzzing (instead of the lighter version of googletest used for unit testing)
24+
25+
gcc_toolchain("chip_pw_fuzztest") {
26+
forward_variables_from(pw_target_toolchain_host.clang_fuzz, "*", [ "name" ])
27+
28+
toolchain_args = {
29+
# This is needed to have the defaults passed from pw_target_toolchain_host.clang_fuzz to the current scope
30+
forward_variables_from(defaults, "*")
31+
32+
pw_unit_test_MAIN = "$dir_pw_fuzzer:fuzztest_main"
33+
pw_unit_test_BACKEND = "$dir_pw_fuzzer:gtest"
34+
35+
# The next three lines are needed by the gcc_toolchain template
36+
current_os = host_os
37+
current_cpu = host_cpu
38+
is_clang = true
39+
40+
# the upstream pigweed host_clang toolchain defines a default sysroot, which results in build errors
41+
# since it does not include SSL lib and is supposed to be minimal by design.
42+
# by removing this default config, we will use the system's libs. Otherwise we can define our own sysroot.
43+
# discussion on: https://discord.com/channels/691686718377558037/1275092695764959232
44+
remove_default_configs = [ "$dir_pw_toolchain/host_clang:linux_sysroot" ]
45+
46+
# when is_debug = true, we pass -O0 to cflags and ldflags, while upstream pw_fuzzer toolchain defines "optimize_speed" config that passes -O2.
47+
# This condition was added to prevent mixing the flags
48+
if (is_debug) {
49+
remove_default_configs += [ "$dir_pw_build:optimize_speed" ]
50+
}
51+
52+
# removing pigweed downstreamed configs related to warnings
53+
# These are triggering an error related to -Wcast-qual in third_party/nlio
54+
remove_default_configs += [
55+
"$dir_pw_build:strict_warnings",
56+
"$dir_pw_build:extra_strict_warnings",
57+
]
58+
59+
# the third_party abseil-cpp triggers warnings related to [-Wformat-nonliteral]
60+
treat_warnings_as_errors = false
61+
62+
dir_pw_third_party_abseil_cpp = "//third_party/abseil-cpp/src"
63+
dir_pw_third_party_fuzztest = "//third_party/fuzztest"
64+
dir_pw_third_party_googletest = "//third_party/googletest"
65+
66+
# TODO: Seems that re2 support within FuzzTest was deprecated, keeping it defined is triggering warning
67+
# Remove if re2 is indeed not needed
68+
# dir_pw_third_party_re2 = "//third_party/re2/src"
69+
}
70+
}

docs/guides/BUILDING.md

+20
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,26 @@ They pick up environment variables such as `$CFLAGS`, `$CXXFLAGS` and
382382
383383
You likely want `libfuzzer` + `asan` builds instead for local testing.
384384
385+
### `pw_fuzzer` `FuzzTests`
386+
387+
An Alternative way for writing and running Fuzz Tests is Google's `FuzzTest`
388+
framework, integrated through `pw_fuzzer`. The Tests will have to be built and
389+
executed manually.
390+
391+
```
392+
./scripts/build/build_examples.py --target linux-x64-tests-clang-pw-fuzztest build
393+
```
394+
395+
NOTE: `asan` is enabled by default in FuzzTest, so please do not add it in
396+
build_examples.py invocation.
397+
398+
Tests will be located in:
399+
`out/linux-x64-tests-clang-pw-fuzztest/chip_pw_fuzztest/tests/` where
400+
`chip_pw_fuzztest` is the name of the toolchain used.
401+
402+
- Details on How To Run Fuzz Tests in
403+
[Running FuzzTests](https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/fuzz_testing.md)
404+
385405
## Build custom configuration
386406
387407
The build is configured by setting build arguments. These you can set in one of

0 commit comments

Comments
 (0)