Merge pull request #17157 from alalek:issue_17138

This commit is contained in:
Alexander Alekhin 2020-04-27 12:23:44 +00:00
commit ee201f4df5
3 changed files with 78 additions and 26 deletions

View File

@ -225,7 +225,9 @@ class TextFormat::Parser::ParserImpl {
bool allow_unknown_enum,
bool allow_field_number,
bool allow_relaxed_whitespace,
bool allow_partial)
bool allow_partial,
int recursion_limit // backported from 3.8.0
)
: error_collector_(error_collector),
finder_(finder),
parse_info_tree_(parse_info_tree),
@ -238,7 +240,9 @@ class TextFormat::Parser::ParserImpl {
allow_unknown_enum_(allow_unknown_enum),
allow_field_number_(allow_field_number),
allow_partial_(allow_partial),
had_errors_(false) {
had_errors_(false),
recursion_limit_(recursion_limit) // backported from 3.8.0
{
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
// for floats.
tokenizer_.set_allow_f_after_float(true);
@ -490,9 +494,9 @@ class TextFormat::Parser::ParserImpl {
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
UnknownFieldSet* unknown_field = unknown_fields->AddGroup(unknown_fields->field_count());
unknown_field->AddLengthDelimited(0, field_name); // Add a field's name.
return SkipFieldValue(unknown_field);
return SkipFieldValue(unknown_field, recursion_limit_);
} else {
return SkipFieldMessage(unknown_fields);
return SkipFieldMessage(unknown_fields, recursion_limit_);
}
}
@ -575,7 +579,14 @@ label_skip_parsing:
}
// Skips the next field including the field's name and value.
bool SkipField(UnknownFieldSet* unknown_fields) {
bool SkipField(UnknownFieldSet* unknown_fields, int recursion_limit) {
// OpenCV specific
if (--recursion_limit < 0) {
ReportError("Message is too deep (SkipField)");
return false;
}
string field_name;
if (TryConsume("[")) {
// Extension name.
@ -594,9 +605,9 @@ label_skip_parsing:
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
UnknownFieldSet* unknown_field = unknown_fields->AddGroup(unknown_fields->field_count());
unknown_field->AddLengthDelimited(0, field_name); // Add a field's name.
DO(SkipFieldValue(unknown_field));
DO(SkipFieldValue(unknown_field, recursion_limit));
} else {
DO(SkipFieldMessage(unknown_fields));
DO(SkipFieldMessage(unknown_fields, recursion_limit));
}
// For historical reasons, fields may optionally be separated by commas or
// semicolons.
@ -608,6 +619,12 @@ label_skip_parsing:
const Reflection* reflection,
const FieldDescriptor* field) {
// backported from 3.8.0
if (--recursion_limit_ < 0) {
ReportError("Message is too deep");
return false;
}
// If the parse information tree is not NULL, create a nested one
// for the nested message.
ParseInfoTree* parent = parse_info_tree_;
@ -624,6 +641,9 @@ label_skip_parsing:
delimiter));
}
// backported from 3.8.0
++recursion_limit_;
// Reset the parse information tree.
parse_info_tree_ = parent;
return true;
@ -631,11 +651,17 @@ label_skip_parsing:
// Skips the whole body of a message including the beginning delimiter and
// the ending delimiter.
bool SkipFieldMessage(UnknownFieldSet* unknown_fields) {
bool SkipFieldMessage(UnknownFieldSet* unknown_fields, int recursion_limit) {
// OpenCV specific
if (--recursion_limit < 0) {
ReportError("Message is too deep (SkipFieldMessage)");
return false;
}
string delimiter;
DO(ConsumeMessageDelimiter(&delimiter));
while (!LookingAt(">") && !LookingAt("}")) {
DO(SkipField(unknown_fields));
DO(SkipField(unknown_fields, recursion_limit));
}
DO(Consume(delimiter));
return true;
@ -775,7 +801,14 @@ label_skip_parsing:
return true;
}
bool SkipFieldValue(UnknownFieldSet* unknown_field) {
bool SkipFieldValue(UnknownFieldSet* unknown_field, int recursion_limit) {
// OpenCV specific
if (--recursion_limit < 0) {
ReportError("Message is too deep (SkipFieldValue)");
return false;
}
if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
tokenizer_.Next();
@ -785,9 +818,9 @@ label_skip_parsing:
if (TryConsume("[")) {
while (true) {
if (!LookingAt("{") && !LookingAt("<")) {
DO(SkipFieldValue(unknown_field));
DO(SkipFieldValue(unknown_field, recursion_limit));
} else {
DO(SkipFieldMessage(unknown_field));
DO(SkipFieldMessage(unknown_field, recursion_limit));
}
if (TryConsume("]")) {
break;
@ -1156,6 +1189,7 @@ label_skip_parsing:
const bool allow_field_number_;
const bool allow_partial_;
bool had_errors_;
int recursion_limit_; // backported from 3.8.0
};
#undef DO
@ -1306,17 +1340,19 @@ class TextFormat::Printer::TextGenerator
TextFormat::Finder::~Finder() {
}
TextFormat::Parser::Parser(bool allow_unknown_field)
TextFormat::Parser::Parser()
: error_collector_(NULL),
finder_(NULL),
parse_info_tree_(NULL),
allow_partial_(false),
allow_case_insensitive_field_(false),
allow_unknown_field_(allow_unknown_field),
allow_unknown_field_(false),
allow_unknown_enum_(false),
allow_field_number_(false),
allow_relaxed_whitespace_(false),
allow_singular_overwrites_(false) {
allow_singular_overwrites_(false),
recursion_limit_(std::numeric_limits<int>::max())
{
}
TextFormat::Parser::~Parser() {}
@ -1335,7 +1371,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
overwrites_policy,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
allow_relaxed_whitespace_, allow_partial_);
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
return MergeUsingImpl(input, output, &parser);
}
@ -1353,7 +1389,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
allow_relaxed_whitespace_, allow_partial_);
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
return MergeUsingImpl(input, output, &parser);
}
@ -1388,7 +1424,7 @@ bool TextFormat::Parser::ParseFieldValueFromString(
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
allow_case_insensitive_field_, allow_unknown_field_,
allow_unknown_enum_, allow_field_number_,
allow_relaxed_whitespace_, allow_partial_);
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
return parser.ParseField(field, output);
}

View File

@ -457,7 +457,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
// For more control over parsing, use this class.
class LIBPROTOBUF_EXPORT Parser {
public:
Parser(bool allow_unknown_field = false);
Parser();
~Parser();
// Like TextFormat::Parse().
@ -508,10 +508,24 @@ class LIBPROTOBUF_EXPORT TextFormat {
Message* output);
// backported from 3.8.0
// When an unknown field is met, parsing will fail if this option is set
// to false(the default). If true, unknown fields will be ignored and
// a warning message will be generated.
// Please aware that set this option true may hide some errors (e.g.
// spelling error on field name). Avoid to use this option if possible.
void AllowUnknownField(bool allow) { allow_unknown_field_ = allow; }
void AllowFieldNumber(bool allow) {
allow_field_number_ = allow;
}
// backported from 3.8.0
// Sets maximum recursion depth which parser can use. This is effectively
// the maximum allowed nesting of proto messages.
void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
private:
// Forward declaration of an internal class used to parse text
// representations (see text_format.cc for implementation).
@ -533,6 +547,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
bool allow_field_number_;
bool allow_relaxed_whitespace_;
bool allow_singular_overwrites_;
int recursion_limit_; // backported from 3.8.0
};

View File

@ -1120,11 +1120,12 @@ bool ReadProtoFromTextFile(const char* filename, Message* proto) {
std::ifstream fs(filename, std::ifstream::in);
CHECK(fs.is_open()) << "Can't open \"" << filename << "\"";
IstreamInputStream input(&fs);
google::protobuf::TextFormat::Parser parser;
#ifndef OPENCV_DNN_EXTERNAL_PROTOBUF
return google::protobuf::TextFormat::Parser(true).Parse(&input, proto);
#else
return google::protobuf::TextFormat::Parser().Parse(&input, proto);
parser.AllowUnknownField(true);
parser.SetRecursionLimit(1000);
#endif
return parser.Parse(&input, proto);
}
bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
@ -1137,12 +1138,12 @@ bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
bool ReadProtoFromTextBuffer(const char* data, size_t len, Message* proto) {
ArrayInputStream input(data, len);
google::protobuf::TextFormat::Parser parser;
#ifndef OPENCV_DNN_EXTERNAL_PROTOBUF
return google::protobuf::TextFormat::Parser(true).Parse(&input, proto);
#else
return google::protobuf::TextFormat::Parser().Parse(&input, proto);
parser.AllowUnknownField(true);
parser.SetRecursionLimit(1000);
#endif
return parser.Parse(&input, proto);
}