[fuzzing] Add dep on google fuzz test (#32578)

Initial PR to establish a bazel dependency on
https://github.com/google/fuzztest, with which I'm planning on basing a
hardening program.

Casting a relatively wide net with reviewers: I'm genuinely interested
in feedback building up the docs, and general ergonomics of this change.

I've located relevant files in the `fuzztest/...` directory. The tests
only build with the `--config fuzztest` bazel argument for now (because
of needing C++17), so locating them separately keeps `bazel test
test/...` working as it does today. In a few years time, when we adopt
C++17, we'll be able to rationalize the test directories a little bit.

We'll need to add some kokoro jobs (maybe with this PR?) to execute the
relevant tests.

<!--

If you know who should review your pull request, please assign it to
that
person, otherwise the pull request would get assigned randomly.

If your pull request is for a specific language, please add the
appropriate
lang label.

-->

---------

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/32666/head
Craig Tiller 2 years ago committed by GitHub
parent c43d37c956
commit dbb131b193
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      bazel/grpc_deps.bzl
  2. 25
      fuzztest/BUILD
  3. 7
      fuzztest/README.md
  4. 24
      fuzztest/fuzztest_test.cc
  5. 28
      fuzztest/grpc_fuzz_test.bzl
  6. 5
      test/distrib/bazel/test_single_bazel_version.sh
  7. 3
      tools/bazel.rc
  8. 1
      tools/distrib/check_copyright.py
  9. 2
      tools/distrib/check_include_guards.py
  10. 1
      tools/distrib/check_naked_includes.py
  11. 22
      tools/distrib/fix_build_deps.py
  12. 1
      tools/distrib/iwyu.sh
  13. 2
      tools/dockerfile/grpc_iwyu/iwyu.sh
  14. 43
      tools/fuzztest.bazelrc
  15. 5
      tools/run_tests/sanity/check_bazel_workspace.py

@ -259,6 +259,17 @@ def grpc_deps():
], ],
) )
if "com_google_fuzztest" not in native.existing_rules():
http_archive(
name = "com_google_fuzztest",
sha256 = "f7bb5b3bd162576f3fbbe9bb768b57931fdd98581c1818789aceee5be4eeee64",
strip_prefix = "fuzztest-62cf00c7341eb05d128d0a3cbce79ac31dbda032",
urls = [
# 2023-03-03
"https://github.com/google/fuzztest/archive/62cf00c7341eb05d128d0a3cbce79ac31dbda032.tar.gz",
],
)
if "rules_cc" not in native.existing_rules(): if "rules_cc" not in native.existing_rules():
http_archive( http_archive(
name = "rules_cc", name = "rules_cc",

@ -0,0 +1,25 @@
# Copyright 2023 gRPC 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.
load(":grpc_fuzz_test.bzl", "grpc_fuzz_test")
grpc_fuzz_test(
name = "fuzztest_test",
srcs = ["fuzztest_test.cc"],
external_deps = ["gtest"],
deps = [
"@com_google_fuzztest//fuzztest",
"@com_google_fuzztest//fuzztest:fuzztest_gtest_main",
],
)

@ -0,0 +1,7 @@
Tests that leverage fuzztest.
These require C++17 and so cannot be run with the standard build configurations.
To run these tests:
bazel run //fuzztest/path/to:test -c dbg --config fuzztest

@ -0,0 +1,24 @@
// Copyright 2023 gRPC 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.
// Test to verify Fuzztest integration
#include "fuzztest/fuzztest.h"
#include "gtest/gtest.h"
TEST(MyTestSuite, OnePlustTwoIsTwoPlusOne) { EXPECT_EQ(1 + 2, 2 + 1); }
void IntegerAdditionCommutes(int a, int b) { EXPECT_EQ(a + b, b + a); }
FUZZ_TEST(MyTestSuite, IntegerAdditionCommutes);

@ -0,0 +1,28 @@
# Copyright 2023 gRPC 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.
"""
Rules for using fuzztest.
"""
load("//bazel:grpc_build_system.bzl", "grpc_cc_test")
def grpc_fuzz_test(name, srcs = [], deps = [], tags = [], external_deps = []):
grpc_cc_test(
name = name,
srcs = srcs,
tags = tags + ["grpc-fuzzer", "no-cache"],
deps = deps,
external_deps = external_deps,
)

@ -30,6 +30,10 @@ EXCLUDED_TARGETS=(
"-//src/objective-c/..." "-//src/objective-c/..."
"-//third_party/objective_c/..." "-//third_party/objective_c/..."
# Targets here need C++17 to build via a different configuration, so this is
# done separately
"-//fuzztest/..."
# This could be a legitmate failure due to bitrot. # This could be a legitmate failure due to bitrot.
"-//src/proto/grpc/testing:test_gen_proto" "-//src/proto/grpc/testing:test_gen_proto"
@ -57,6 +61,7 @@ ACTION_ENV_FLAG="--action_env=bazel_cache_invalidate=version_${VERSION}"
tools/bazel version | grep "$VERSION" || { echo "Detected bazel version did not match expected value of $VERSION" >/dev/stderr; exit 1; } tools/bazel version | grep "$VERSION" || { echo "Detected bazel version did not match expected value of $VERSION" >/dev/stderr; exit 1; }
tools/bazel build "${ACTION_ENV_FLAG}" -- //... "${EXCLUDED_TARGETS[@]}" || FAILED_TESTS="${FAILED_TESTS}buildtest " tools/bazel build "${ACTION_ENV_FLAG}" -- //... "${EXCLUDED_TARGETS[@]}" || FAILED_TESTS="${FAILED_TESTS}buildtest "
tools/bazel build "${ACTION_ENV_FLAG}" --config fuzztest -- //fuzztest/... || FAILED_TESTS="${FAILED_TESTS}fuzztest_buildtest "
for TEST_DIRECTORY in "${TEST_DIRECTORIES[@]}"; do for TEST_DIRECTORY in "${TEST_DIRECTORIES[@]}"; do
pushd "test/distrib/bazel/$TEST_DIRECTORY/" pushd "test/distrib/bazel/$TEST_DIRECTORY/"

@ -142,3 +142,6 @@ build:python_poller_engine --test_env="GRPC_ASYNCIO_ENGINE=poller"
# Compile database generation config # Compile database generation config
build:compdb --build_tag_filters=-nocompdb --features=-layering_check build:compdb --build_tag_filters=-nocompdb --features=-layering_check
try-import %workspace%/tools/fuzztest.bazelrc
build:fuzztest --cxxopt=-std=c++17

@ -142,6 +142,7 @@ _ENFORCE_CPP_STYLE_COMMENT_PATH_PREFIX = tuple([
'src/cpp/', 'src/cpp/',
'test/core/', 'test/core/',
'test/cpp/', 'test/cpp/',
'fuzztest/',
]) ])
RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+) ([Tt]he )?gRPC [Aa]uthors(\.|)' RE_YEAR = r'Copyright (?P<first_year>[0-9]+\-)?(?P<last_year>[0-9]+) ([Tt]he )?gRPC [Aa]uthors(\.|)'

@ -189,7 +189,7 @@ argp.add_argument('-f', '--fix', default=False, action='store_true')
argp.add_argument('--precommit', default=False, action='store_true') argp.add_argument('--precommit', default=False, action='store_true')
args = argp.parse_args() args = argp.parse_args()
grep_filter = r"grep -E '^(include|src/core|src/cpp|test/core|test/cpp)/.*\.h$'" grep_filter = r"grep -E '^(include|src/core|src/cpp|test/core|test/cpp|fuzztest/)/.*\.h$'"
if args.precommit: if args.precommit:
git_command = 'git diff --name-only HEAD' git_command = 'git diff --name-only HEAD'
else: else:

@ -38,6 +38,7 @@ CHECK_SUBDIRS = [
'src/cpp', 'src/cpp',
'test/core', 'test/core',
'test/cpp', 'test/cpp',
'fuzztest',
] ]
for subdir in CHECK_SUBDIRS: for subdir in CHECK_SUBDIRS:

@ -221,6 +221,10 @@ EXTERNAL_DEPS = {
} }
INTERNAL_DEPS = { INTERNAL_DEPS = {
'fuzztest/fuzztest.h': [
'@com_google_fuzztest//fuzztest',
'@com_google_fuzztest//fuzztest:fuzztest_gtest_main'
],
'google/api/expr/v1alpha1/syntax.upb.h': 'google/api/expr/v1alpha1/syntax.upb.h':
'google_type_expr_upb', 'google_type_expr_upb',
'google/rpc/status.upb.h': 'google/rpc/status.upb.h':
@ -433,6 +437,7 @@ for dirname in [
"test/core/promise", "test/core/promise",
"test/core/resource_quota", "test/core/resource_quota",
"test/core/transport/chaotic_good", "test/core/transport/chaotic_good",
"fuzztest",
]: ]:
parsing_path = dirname parsing_path = dirname
exec( exec(
@ -448,6 +453,7 @@ for dirname in [
'grpc_cc_library': grpc_cc_library, 'grpc_cc_library': grpc_cc_library,
'grpc_cc_test': grpc_cc_library, 'grpc_cc_test': grpc_cc_library,
'grpc_fuzzer': grpc_cc_library, 'grpc_fuzzer': grpc_cc_library,
'grpc_fuzz_test': grpc_cc_library,
'grpc_proto_fuzzer': grpc_cc_library, 'grpc_proto_fuzzer': grpc_cc_library,
'select': lambda d: d["//conditions:default"], 'select': lambda d: d["//conditions:default"],
'glob': lambda files: None, 'glob': lambda files: None,
@ -570,9 +576,13 @@ def make_library(library):
if hdr in INTERNAL_DEPS: if hdr in INTERNAL_DEPS:
dep = INTERNAL_DEPS[hdr] dep = INTERNAL_DEPS[hdr]
if not ('//' in dep): if isinstance(dep, list):
dep = '//:' + dep for d in dep:
deps.add(dep, hdr) deps.add(d, hdr)
else:
if not ('//' in dep):
dep = '//:' + dep
deps.add(dep, hdr)
continue continue
if hdr in vendors: if hdr in vendors:
@ -588,7 +598,11 @@ def make_library(library):
continue continue
if hdr in EXTERNAL_DEPS: if hdr in EXTERNAL_DEPS:
external_deps.add(EXTERNAL_DEPS[hdr], hdr) if isinstance(EXTERNAL_DEPS[hdr], list):
for dep in EXTERNAL_DEPS[hdr]:
external_deps.add(dep, hdr)
else:
external_deps.add(EXTERNAL_DEPS[hdr], hdr)
continue continue
if hdr.startswith('opencensus/'): if hdr.startswith('opencensus/'):

@ -35,6 +35,7 @@ tools/distrib/gen_compilation_database.py \
"//src/compiler/..." \ "//src/compiler/..." \
"//test/core/..." \ "//test/core/..." \
"//test/cpp/..." \ "//test/cpp/..." \
"//fuzztest/..." \
$MANUAL_TARGETS $MANUAL_TARGETS
# run iwyu against the checked out codebase # run iwyu against the checked out codebase

@ -66,6 +66,7 @@ sed -i 's,^#!/usr/bin/env python,#!/usr/bin/env python3,g' ${IWYU_ROOT}/iwyu/fix
cat compile_commands.json \ cat compile_commands.json \
| sed "s/ -DNDEBUG//g" \ | sed "s/ -DNDEBUG//g" \
| sed "s/ -std=c\\+\\+14/ -std=c++17/g" \
| sed "s,\"file\": \",\"file\": \"${IWYU_ROOT}/,g" \ | sed "s,\"file\": \",\"file\": \"${IWYU_ROOT}/,g" \
> compile_commands_for_iwyu.json > compile_commands_for_iwyu.json
@ -74,6 +75,7 @@ export ENABLED_MODULES='
src/core/lib src/core/lib
src/cpp src/cpp
test/core test/core
fuzztest
' '
export DISABLED_MODULES=' export DISABLED_MODULES='

@ -0,0 +1,43 @@
### DO NOT EDIT. Generated file.
#
# To regenerate, run the following from your project's workspace:
#
# bazel run @com_google_fuzztest//bazel:setup_configs > fuzztest.bazelrc
#
# And don't forget to add the following to your project's .bazelrc:
#
# try-import %workspace%/fuzztest.bazelrc
### Common options.
#
# Do not use directly.
# Link with Address Sanitizer (ASAN).
build:fuzztest-common --linkopt=-fsanitize=address
# Standard define for "ifdef-ing" any fuzz test specific code.
build:fuzztest-common --copt=-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
# In fuzz tests, we want to catch assertion violations even in optimized builds.
build:fuzztest-common --copt=-UNDEBUG
### FuzzTest build configuration.
#
# Use with: --config=fuzztest
build:fuzztest --config=fuzztest-common
# Link statically.
build:fuzztest --dynamic_mode=off
# We rely on the following flag instead of the compiler provided
# __has_feature(address_sanitizer) to know that we have an ASAN build even in
# the uninstrumented runtime.
build:fuzztest --copt=-DADDRESS_SANITIZER
# We apply coverage tracking and ASAN instrumentation to everything but the
# FuzzTest framework itself (including GoogleTest and GoogleMock).
build:fuzztest --per_file_copt=+//,-fuzztest/.*,-googletest/.*,-googlemock/.*@-fsanitize=address,-fsanitize-coverage=inline-8bit-counters,-fsanitize-coverage=trace-cmp

@ -43,8 +43,8 @@ _TWISTED_CONSTANTLY_DEP_NAME = 'com_github_twisted_constantly'
_GRPC_DEP_NAMES = [ _GRPC_DEP_NAMES = [
'upb', 'boringssl', 'zlib', 'com_google_protobuf', 'com_google_googletest', 'upb', 'boringssl', 'zlib', 'com_google_protobuf', 'com_google_googletest',
'rules_cc', 'com_github_google_benchmark', 'com_github_cares_cares', 'rules_cc', 'com_github_google_benchmark', 'com_github_cares_cares',
'com_google_absl', 'io_opencensus_cpp', 'envoy_api', _BAZEL_SKYLIB_DEP_NAME, 'com_google_absl', 'com_google_fuzztest', 'io_opencensus_cpp', 'envoy_api',
_BAZEL_TOOLCHAINS_DEP_NAME, _BAZEL_COMPDB_DEP_NAME, _BAZEL_SKYLIB_DEP_NAME, _BAZEL_TOOLCHAINS_DEP_NAME, _BAZEL_COMPDB_DEP_NAME,
_TWISTED_TWISTED_DEP_NAME, _YAML_PYYAML_DEP_NAME, _TWISTED_TWISTED_DEP_NAME, _YAML_PYYAML_DEP_NAME,
_TWISTED_INCREMENTAL_DEP_NAME, _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME, _TWISTED_INCREMENTAL_DEP_NAME, _ZOPEFOUNDATION_ZOPE_INTERFACE_DEP_NAME,
_TWISTED_CONSTANTLY_DEP_NAME, 'io_bazel_rules_go', _TWISTED_CONSTANTLY_DEP_NAME, 'io_bazel_rules_go',
@ -59,6 +59,7 @@ _GRPC_BAZEL_ONLY_DEPS = [
'upb', # third_party/upb is checked in locally 'upb', # third_party/upb is checked in locally
'rules_cc', 'rules_cc',
'com_google_absl', 'com_google_absl',
'com_google_fuzztest',
'io_opencensus_cpp', 'io_opencensus_cpp',
_BAZEL_SKYLIB_DEP_NAME, _BAZEL_SKYLIB_DEP_NAME,
_BAZEL_TOOLCHAINS_DEP_NAME, _BAZEL_TOOLCHAINS_DEP_NAME,

Loading…
Cancel
Save