PiperOrigin-RevId: 458240180pull/13171/head
parent
d44834063a
commit
125db89ff5
9 changed files with 365 additions and 16 deletions
@ -0,0 +1,190 @@ |
||||
/*
|
||||
* Copyright (c) 2009-2022, Google LLC |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* * Neither the name of Google LLC nor the |
||||
* names of its contributors may be used to endorse or promote products |
||||
* derived from this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#include "upb/fuzz_test_util.h" |
||||
|
||||
#include "upb/msg.h" |
||||
#include "upb/upb.hpp" |
||||
|
||||
namespace upb { |
||||
namespace fuzz { |
||||
|
||||
namespace { |
||||
|
||||
class Builder { |
||||
public: |
||||
Builder(const MiniTableFuzzInput& input, upb_Arena* arena) |
||||
: input_(&input), arena_(arena) {} |
||||
|
||||
const upb_MiniTable* Build(upb_ExtensionRegistry** exts) { |
||||
BuildMessages(); |
||||
BuildEnums(); |
||||
BuildExtensions(exts); |
||||
LinkMessages(); |
||||
return mini_tables_.empty() ? nullptr : mini_tables_.front(); |
||||
} |
||||
|
||||
private: |
||||
void BuildMessages(); |
||||
void BuildEnums(); |
||||
void BuildExtensions(upb_ExtensionRegistry** exts); |
||||
bool LinkExtension(upb_MiniTable_Extension* ext); |
||||
void LinkMessages(); |
||||
|
||||
size_t NextLink() { |
||||
if (input_->links.empty()) return 0; |
||||
if (link_ == input_->links.size()) link_ = 0; |
||||
return input_->links[link_++]; |
||||
} |
||||
|
||||
const upb_MiniTable* NextMiniTable() { |
||||
return mini_tables_.empty() |
||||
? nullptr |
||||
: mini_tables_[NextLink() % mini_tables_.size()]; |
||||
} |
||||
|
||||
const upb_MiniTable_Enum* NextEnumTable() { |
||||
return enum_tables_.empty() |
||||
? nullptr |
||||
: enum_tables_[NextLink() % enum_tables_.size()]; |
||||
} |
||||
|
||||
const MiniTableFuzzInput* input_; |
||||
upb_Arena* arena_; |
||||
std::vector<const upb_MiniTable*> mini_tables_; |
||||
std::vector<const upb_MiniTable_Enum*> enum_tables_; |
||||
size_t link_ = 0; |
||||
}; |
||||
|
||||
void Builder::BuildMessages() { |
||||
upb::Status status; |
||||
mini_tables_.reserve(input_->mini_descriptors.size()); |
||||
for (const auto& d : input_->mini_descriptors) { |
||||
upb_MiniTable* table; |
||||
if (d == "\n") { |
||||
// We special-case this input string, which is not a valid
|
||||
// mini-descriptor, to mean message set.
|
||||
table = |
||||
upb_MiniTable_BuildMessageSet(kUpb_MiniTablePlatform_Native, arena_); |
||||
} else { |
||||
table = |
||||
upb_MiniTable_Build(d.data(), d.size(), kUpb_MiniTablePlatform_Native, |
||||
arena_, status.ptr()); |
||||
} |
||||
if (table) mini_tables_.push_back(table); |
||||
} |
||||
} |
||||
|
||||
void Builder::BuildEnums() { |
||||
upb::Status status; |
||||
enum_tables_.reserve(input_->enum_mini_descriptors.size()); |
||||
for (const auto& d : input_->enum_mini_descriptors) { |
||||
upb_MiniTable_Enum* enum_table = |
||||
upb_MiniTable_BuildEnum(d.data(), d.size(), arena_, status.ptr()); |
||||
if (enum_table) enum_tables_.push_back(enum_table); |
||||
} |
||||
} |
||||
|
||||
bool Builder::LinkExtension(upb_MiniTable_Extension* ext) { |
||||
upb_MiniTable_Field* field = &ext->field; |
||||
ext->extendee = NextMiniTable(); |
||||
if (!ext->extendee) return false; |
||||
if (field->descriptortype == kUpb_FieldType_Message || |
||||
field->descriptortype == kUpb_FieldType_Group) { |
||||
auto mt = NextMiniTable(); |
||||
if (!mt) field->descriptortype = kUpb_FieldType_Int32; |
||||
ext->sub.submsg = mt; |
||||
} |
||||
if (field->descriptortype == kUpb_FieldType_Enum) { |
||||
auto et = NextEnumTable(); |
||||
if (!et) field->descriptortype = kUpb_FieldType_Int32; |
||||
ext->sub.subenum = et; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
void Builder::BuildExtensions(upb_ExtensionRegistry** exts) { |
||||
upb::Status status; |
||||
if (input_->extensions.empty()) { |
||||
*exts = nullptr; |
||||
} else { |
||||
*exts = upb_ExtensionRegistry_New(arena_); |
||||
const char* ptr = input_->extensions.data(); |
||||
const char* end = ptr + input_->extensions.size(); |
||||
// Iterate through the buffer, building extensions as long as we can.
|
||||
while (ptr < end) { |
||||
upb_MiniTable_Extension* ext = reinterpret_cast<upb_MiniTable_Extension*>( |
||||
upb_Arena_Malloc(arena_, sizeof(*ext))); |
||||
upb_MiniTable_Sub sub; |
||||
ptr = |
||||
upb_MiniTable_BuildExtension(ptr, end - ptr, ext, sub, status.ptr()); |
||||
if (!ptr) break; |
||||
if (!LinkExtension(ext)) continue; |
||||
if (_upb_extreg_get(*exts, ext->extendee, ext->field.number)) continue; |
||||
_upb_extreg_add(*exts, const_cast<const upb_MiniTable_Extension**>(&ext), |
||||
1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Builder::LinkMessages() { |
||||
for (auto* t : mini_tables_) { |
||||
upb_MiniTable* table = const_cast<upb_MiniTable*>(t); |
||||
// For each field that requires a sub-table, assign one as appropriate.
|
||||
for (size_t i = 0; i < table->field_count; i++) { |
||||
upb_MiniTable_Field* field = |
||||
const_cast<upb_MiniTable_Field*>(&table->fields[i]); |
||||
if (link_ == input_->links.size()) link_ = 0; |
||||
if (field->descriptortype == kUpb_FieldType_Message || |
||||
field->descriptortype == kUpb_FieldType_Group) { |
||||
upb_MiniTable_SetSubMessage(table, field, NextMiniTable()); |
||||
} |
||||
if (field->descriptortype == kUpb_FieldType_Enum) { |
||||
auto* et = NextEnumTable(); |
||||
if (et) { |
||||
upb_MiniTable_SetSubEnum(table, field, et); |
||||
} else { |
||||
// We don't have any sub-enums. Override the field type so that it is
|
||||
// not needed.
|
||||
field->descriptortype = kUpb_FieldType_Int32; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
const upb_MiniTable* BuildMiniTable(const MiniTableFuzzInput& input, |
||||
upb_ExtensionRegistry** exts, |
||||
upb_Arena* arena) { |
||||
Builder builder(input, arena); |
||||
return builder.Build(exts); |
||||
} |
||||
|
||||
} // namespace fuzz
|
||||
} // namespace upb
|
@ -0,0 +1,80 @@ |
||||
/*
|
||||
* Copyright (c) 2009-2022, Google LLC |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are met: |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* * Neither the name of Google LLC nor the |
||||
* names of its contributors may be used to endorse or promote products |
||||
* derived from this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, |
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#ifndef UPB_FUZZ_TEST_UTIL_H_ |
||||
#define UPB_FUZZ_TEST_UTIL_H_ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "upb/mini_table.h" |
||||
|
||||
namespace upb { |
||||
namespace fuzz { |
||||
|
||||
struct MiniTableFuzzInput { |
||||
// MiniDescripotrs for N messages, in the format accepted by
|
||||
// upb_MiniTable_Build().
|
||||
std::vector<std::string> mini_descriptors; |
||||
|
||||
// MiniDescripotrs for N enums, in the format accepted by
|
||||
// upb_MiniTable_BuildEnum().
|
||||
std::vector<std::string> enum_mini_descriptors; |
||||
|
||||
// A MiniDescriptor for N extensions, in the format accepted by
|
||||
// upb_MiniTable_BuildExtension().
|
||||
std::string extensions; |
||||
|
||||
// Integer indexes into the message or enum mini tables lists. These specify
|
||||
// which message or enum to use for each sub-message or enum field. We mod
|
||||
// by the total number of enums or messages so that any link value can be
|
||||
// valid.
|
||||
std::vector<uint32_t> links; |
||||
}; |
||||
|
||||
// Builds an arbitrary mini table corresponding to the random data in `input`.
|
||||
// This function should be capable of producing any mini table that can
|
||||
// successfully build, and any topology of messages and enums (including
|
||||
// cycles).
|
||||
//
|
||||
// As currently written, it effectively fuzzes the mini descriptor parser also,
|
||||
// and can therefore trigger any bugs in that parser. To better isolate these
|
||||
// two, we may want to change this implementation to use the mini descriptor
|
||||
// builder API so we are producing mini descriptors in a known good format. That
|
||||
// would mostly eliminate the chance of crashing the mini descriptor parser
|
||||
// itself.
|
||||
//
|
||||
// TODO: maps. If we give maps some space in the regular encoding instead of
|
||||
// using a separate function, we could get that for free.
|
||||
const upb_MiniTable* BuildMiniTable(const MiniTableFuzzInput& input, |
||||
upb_ExtensionRegistry** exts, |
||||
upb_Arena* arena); |
||||
|
||||
} // namespace fuzz
|
||||
} // namespace upb
|
||||
|
||||
#endif // THIRD_PARTY_UPB_UPB_FUZZ_TEST_UTIL_H_
|
Loading…
Reference in new issue