Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions domain_tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ cc_test(
tags = ["cpu:4"],
deps = [
":domain_testing",
"//third_party/protobuf:descriptor_pb",
"@protobuf//:differencer",
"@abseil-cpp//absl/container:flat_hash_set",
"@abseil-cpp//absl/random",
Expand Down
30 changes: 30 additions & 0 deletions domain_tests/arbitrary_domains_protobuf_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
#include "./domain_tests/domain_testing.h"
#include "./fuzztest/internal/test_protobuf.pb.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/message.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/util/message_differencer.h"
Expand Down Expand Up @@ -853,5 +855,33 @@ TEST(ProtobufDomainTest, LastMaxSizeSettingWins) {
EXPECT_TRUE(domain2.ValidateCorpusValue(*corpus2).ok());
}

TEST(ProtobufDomainTest, EnsureNoUseAfterFreeAcrossDynamicPoolDestructions) {
google::protobuf::FileDescriptorProto file_proto;
file_proto.set_name("dynamic_test.proto");
auto* message_proto = file_proto.add_message_type();
message_proto->set_name("DynamicTestMessage");
auto* field = message_proto->add_field();
field->set_name("dynamic_field");
field->set_number(1);
field->set_type(google::protobuf::FieldDescriptorProto::TYPE_INT32);

for (int i = 0; i < 10; ++i) {
google::protobuf::DescriptorPool pool;
const google::protobuf::FileDescriptor* file_desc = pool.BuildFile(file_proto);
ASSERT_NE(file_desc, nullptr);
const google::protobuf::Descriptor* message_desc =
file_desc->FindMessageTypeByName("DynamicTestMessage");
ASSERT_NE(message_desc, nullptr);

google::protobuf::DynamicMessageFactory factory(&pool);
const google::protobuf::Message* prototype = factory.GetPrototype(message_desc);
ASSERT_NE(prototype, nullptr);

auto domain = ProtobufOf([prototype] { return prototype; });
auto values = GenerateInitialValues(domain, 10);
EXPECT_FALSE(values.empty());
}
}

} // namespace
} // namespace fuzztest
44 changes: 29 additions & 15 deletions fuzztest/internal/domains/protobuf_domain_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,31 +364,45 @@ class ProtoPolicy {
return caches_->SetFields(descriptor, GetProtobufFields(descriptor));
}

static const std::vector<const FieldDescriptor*>& GetProtobufFields(
static std::vector<const FieldDescriptor*> GetProtobufFields(
const ProtoDescriptor* descriptor) {
ABSL_CONST_INIT static absl::Mutex mutex(absl::kConstInit);
static absl::NoDestructor<absl::flat_hash_map<
const ProtoDescriptor*,
std::unique_ptr<std::vector<const FieldDescriptor*>>>>
descriptor_to_fields ABSL_GUARDED_BY(mutex);
{
const auto* pool = descriptor->file()->pool();
const bool is_generated_pool = (pool == pool->generated_pool());
if (is_generated_pool) {
ABSL_CONST_INIT static absl::Mutex mutex(absl::kConstInit);
static absl::NoDestructor<absl::flat_hash_map<
const ProtoDescriptor*,
std::unique_ptr<std::vector<const FieldDescriptor*>>>>
descriptor_to_fields ABSL_GUARDED_BY(mutex);
{
absl::MutexLock l(mutex);
auto it = descriptor_to_fields->find(descriptor);
if (it != descriptor_to_fields->end()) return *(it->second);
}
std::vector<const FieldDescriptor*> fields;
fields.reserve(descriptor->field_count());
for (int i = 0; i < descriptor->field_count(); ++i) {
fields.push_back(descriptor->field(i));
}
absl::MutexLock l(mutex);
auto it = descriptor_to_fields->find(descriptor);
if (it != descriptor_to_fields->end()) return *(it->second);
if (ShouldEnumerateExtensions(descriptor)) {
pool->FindAllExtensions(descriptor, &fields);
}
auto [it, _] = descriptor_to_fields->insert(
{descriptor, std::make_unique<std::vector<const FieldDescriptor*>>(
std::move(fields))});
return *(it->second);
}

std::vector<const FieldDescriptor*> fields;
fields.reserve(descriptor->field_count());
for (int i = 0; i < descriptor->field_count(); ++i) {
fields.push_back(descriptor->field(i));
}
absl::MutexLock l(mutex);
if (ShouldEnumerateExtensions(descriptor)) {
descriptor->file()->pool()->FindAllExtensions(descriptor, &fields);
pool->FindAllExtensions(descriptor, &fields);
}
auto [it, _] = descriptor_to_fields->insert(
{descriptor, std::make_unique<std::vector<const FieldDescriptor*>>(
std::move(fields))});
return *(it->second);
return fields;
}

private:
Expand Down
Loading