dnn(protobuf): backport AllowUnknownField(), SetRecursionLimit()

- limit recursion in SkipField*() calls
pull/17157/head
Alexander Alekhin 5 years ago
parent 8d05dab32c
commit 288fa70ed9
  1. 72
      3rdparty/protobuf/src/google/protobuf/text_format.cc
  2. 17
      3rdparty/protobuf/src/google/protobuf/text_format.h
  3. 15
      modules/dnn/src/caffe/caffe_io.cpp

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

@ -457,7 +457,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
// For more control over parsing, use this class. // For more control over parsing, use this class.
class LIBPROTOBUF_EXPORT Parser { class LIBPROTOBUF_EXPORT Parser {
public: public:
Parser(bool allow_unknown_field = false); Parser();
~Parser(); ~Parser();
// Like TextFormat::Parse(). // Like TextFormat::Parse().
@ -508,10 +508,24 @@ class LIBPROTOBUF_EXPORT TextFormat {
Message* output); 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) { void AllowFieldNumber(bool allow) {
allow_field_number_ = 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: private:
// Forward declaration of an internal class used to parse text // Forward declaration of an internal class used to parse text
// representations (see text_format.cc for implementation). // representations (see text_format.cc for implementation).
@ -533,6 +547,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
bool allow_field_number_; bool allow_field_number_;
bool allow_relaxed_whitespace_; bool allow_relaxed_whitespace_;
bool allow_singular_overwrites_; bool allow_singular_overwrites_;
int recursion_limit_; // backported from 3.8.0
}; };

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

Loading…
Cancel
Save