[fuzzing] Make it easier for fuzzers to find experiments (#34296)

The previous approach of generating strings was not converging well.
Instead, load a bitfield from the protobuf and use the bits to select
experiments. The fuzzers can explore this space swiftly.

Downside is that as experiments rotate in/out the corpus gets a bit
messed up, but I'm reasonably confident we'll recover quickly.

---------

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/34329/head
Craig Tiller 1 year ago committed by GitHub
parent c9db496000
commit a9bf741735
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      src/core/lib/config/config_vars.yaml
  2. 8
      test/core/end2end/end2end_test_fuzzer.cc
  3. 2
      test/core/util/fuzz_config_vars.proto
  4. 20
      test/core/util/fuzz_config_vars_helpers.cc
  5. 6
      test/core/util/fuzz_config_vars_helpers.h
  6. 4
      tools/codegen/core/gen_config_vars.py

@ -35,6 +35,7 @@
A comma separated list of currently active experiments. Experiments may be
prefixed with a '-' to disable them.
default:
fuzz_type: uint64
fuzz: ValidateExperimentsStringForFuzzing
- name: client_channel_backup_poll_interval_ms
type: int

@ -46,7 +46,6 @@
#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.h"
#include "test/core/event_engine/fuzzing_event_engine/fuzzing_event_engine.pb.h"
#include "test/core/util/fuzz_config_vars.h"
#include "test/core/util/fuzz_config_vars.pb.h"
using ::grpc_event_engine::experimental::FuzzingEventEngine;
using ::grpc_event_engine::experimental::GetDefaultEventEngine;
@ -100,8 +99,6 @@ DEFINE_PROTO_FUZZER(const core_end2end_test_fuzzer::Msg& msg) {
return tests;
}();
if (tests.empty()) return;
static const auto only_experiment =
grpc_core::GetEnv("GRPC_TEST_FUZZER_EXPERIMENT");
const int test_id = msg.test_id() % tests.size();
@ -109,11 +106,6 @@ DEFINE_PROTO_FUZZER(const core_end2end_test_fuzzer::Msg& msg) {
gpr_set_log_function(dont_log);
}
if (only_experiment.has_value() &&
msg.config_vars().experiments() != only_experiment.value()) {
return;
}
// TODO(ctiller): make this per fixture?
grpc_core::ConfigVars::Overrides overrides =
grpc_core::OverridesFromFuzzConfigVars(msg.config_vars());

@ -25,6 +25,6 @@ message FuzzConfigVars {
optional string dns_resolver = 76817901;
optional string verbosity = 68420950;
optional string stacktrace_minloglevel = 273035715;
optional string experiments = 510817011;
optional uint64 experiments = 510817011;
optional string trace = 291231137;
};

@ -13,27 +13,25 @@
// limitations under the License.
#include <stddef.h>
#include <stdint.h>
#include <set>
#include <algorithm>
#include <string>
#include <vector>
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "src/core/lib/experiments/config.h"
#include "src/core/lib/experiments/experiments.h"
namespace grpc_core {
std::string ValidateExperimentsStringForFuzzing(absl::string_view input) {
std::set<absl::string_view> experiments;
for (absl::string_view experiment : absl::StrSplit(input, ',')) {
for (size_t i = 0; i < kNumExperiments; i++) {
const auto& metadata = g_experiment_metadata[i];
if (metadata.name == experiment && metadata.allow_in_fuzzing_config) {
experiments.insert(experiment);
}
std::string ValidateExperimentsStringForFuzzing(uint64_t input) {
std::vector<std::string> experiments;
for (size_t i = 0; i < std::min<size_t>(kNumExperiments, 64); i++) {
const auto& metadata = g_experiment_metadata[i];
if ((input & (1ull << i)) && metadata.allow_in_fuzzing_config) {
experiments.push_back(metadata.name);
}
}
return absl::StrJoin(experiments, ",");

@ -17,13 +17,13 @@
#include <grpc/support/port_platform.h>
#include <string>
#include <stdint.h>
#include "absl/strings/string_view.h"
#include <string>
namespace grpc_core {
std::string ValidateExperimentsStringForFuzzing(absl::string_view experiments);
std::string ValidateExperimentsStringForFuzzing(uint64_t experiments);
} // namespace grpc_core

@ -29,7 +29,7 @@ import sys
import yaml
with open("src/core/lib/config/config_vars.yaml") as f:
attrs = yaml.safe_load(f.read(), Loader=yaml.FullLoader)
attrs = yaml.safe_load(f.read())
error = False
today = datetime.date.today()
@ -199,7 +199,7 @@ with open("test/core/util/fuzz_config_vars.proto", "w") as P:
print(
" optional %s %s = %d;"
% (
PROTO_TYPE[attr["type"]],
attr.get("fuzz_type", PROTO_TYPE[attr["type"]]),
attr["name"],
binascii.crc32(attr["name"].encode("ascii")) & 0x1FFFFFFF,
),

Loading…
Cancel
Save