Mutate newly added fields to protobuf because they can have empty value (e.g., nullopt).
The underlying issue is that, conceptually, the protobuf domain has 2 uninitialized states for each field.
(a) The ProtobufDomain maintains a `map<field_num, field_value>`. If a field is not contained within this map it is considered uninitialized and is unset when converted to a `Message`
(b) fields are represented with `std::optional<field_type>`/`std::vector<field_type>` domain. If the field is empty (e.g., `std::nullopt`) then, similarly, the field is considered uninitialized and is unset when converted to a `Message`.
`Mutate` ends up doing nothing from the perspective of the final output `Message` as we transition between these 2 states. Thus, when adding a field, first we initialize and then perform a mutation to make sure the field is not empty with a high probability.
PiperOrigin-RevId: 795468043
diff --git a/fuzztest/internal/domains/protobuf_domain_impl.h b/fuzztest/internal/domains/protobuf_domain_impl.h
index d329858..278ea8b 100644
--- a/fuzztest/internal/domains/protobuf_domain_impl.h
+++ b/fuzztest/internal/domains/protobuf_domain_impl.h
@@ -1137,16 +1137,15 @@
auto it = val.find(field->number());
const bool is_present = it != val.end();
- if (is_present) {
- // Mutate the element
- domain.Mutate(it->second, prng, metadata, only_shrink);
- return;
- }
-
- // Add the element
- if (!only_shrink) {
+ if (!is_present) {
+ if (only_shrink) return;
+ // Add the element
InitializeFieldValue<T>(prng, self, field, val);
+ // Mutate the new element to generate non-nullopt values.
+ it = val.find(field->number());
}
+ // Mutate the element
+ domain.Mutate(it->second, prng, metadata, only_shrink);
}
template <typename T>
@@ -1156,10 +1155,11 @@
const bool is_present = it != val.end();
if (!is_present) {
- if (!only_shrink) {
- val[field->number()] = domain.Init(prng);
- }
- } else if (field->is_map()) {
+ if (only_shrink) return;
+ // Mutate the field after initialization to generate non-empty values.
+ it = val.insert({field->number(), domain.Init(prng)}).first;
+ }
+ if (field->is_map()) {
// field of synthetic messages of the form:
//
// message {