Skip to content

Commit 9a54a32

Browse files
committed
dnn(protobuf): backport AllowUnknownField(), SetRecursionLimit()
- limit recursion in SkipField*() calls original commit 288fa70
1 parent 9c1e2a6 commit 9a54a32

File tree

3 files changed

+78
-26
lines changed

3 files changed

+78
-26
lines changed

3rdparty/protobuf/src/google/protobuf/text_format.cc

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ class TextFormat::Parser::ParserImpl {
225225
bool allow_unknown_enum,
226226
bool allow_field_number,
227227
bool allow_relaxed_whitespace,
228-
bool allow_partial)
228+
bool allow_partial,
229+
int recursion_limit // backported from 3.8.0
230+
)
229231
: error_collector_(error_collector),
230232
finder_(finder),
231233
parse_info_tree_(parse_info_tree),
@@ -238,7 +240,9 @@ class TextFormat::Parser::ParserImpl {
238240
allow_unknown_enum_(allow_unknown_enum),
239241
allow_field_number_(allow_field_number),
240242
allow_partial_(allow_partial),
241-
had_errors_(false) {
243+
had_errors_(false),
244+
recursion_limit_(recursion_limit) // backported from 3.8.0
245+
{
242246
// For backwards-compatibility with proto1, we need to allow the 'f' suffix
243247
// for floats.
244248
tokenizer_.set_allow_f_after_float(true);
@@ -490,9 +494,9 @@ class TextFormat::Parser::ParserImpl {
490494
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
491495
UnknownFieldSet* unknown_field = unknown_fields->AddGroup(unknown_fields->field_count());
492496
unknown_field->AddLengthDelimited(0, field_name); // Add a field's name.
493-
return SkipFieldValue(unknown_field);
497+
return SkipFieldValue(unknown_field, recursion_limit_);
494498
} else {
495-
return SkipFieldMessage(unknown_fields);
499+
return SkipFieldMessage(unknown_fields, recursion_limit_);
496500
}
497501
}
498502

@@ -575,7 +579,14 @@ class TextFormat::Parser::ParserImpl {
575579
}
576580

577581
// Skips the next field including the field's name and value.
578-
bool SkipField(UnknownFieldSet* unknown_fields) {
582+
bool SkipField(UnknownFieldSet* unknown_fields, int recursion_limit) {
583+
584+
// OpenCV specific
585+
if (--recursion_limit < 0) {
586+
ReportError("Message is too deep (SkipField)");
587+
return false;
588+
}
589+
579590
string field_name;
580591
if (TryConsume("[")) {
581592
// Extension name.
@@ -594,9 +605,9 @@ class TextFormat::Parser::ParserImpl {
594605
if (TryConsume(":") && !LookingAt("{") && !LookingAt("<")) {
595606
UnknownFieldSet* unknown_field = unknown_fields->AddGroup(unknown_fields->field_count());
596607
unknown_field->AddLengthDelimited(0, field_name); // Add a field's name.
597-
DO(SkipFieldValue(unknown_field));
608+
DO(SkipFieldValue(unknown_field, recursion_limit));
598609
} else {
599-
DO(SkipFieldMessage(unknown_fields));
610+
DO(SkipFieldMessage(unknown_fields, recursion_limit));
600611
}
601612
// For historical reasons, fields may optionally be separated by commas or
602613
// semicolons.
@@ -608,6 +619,12 @@ class TextFormat::Parser::ParserImpl {
608619
const Reflection* reflection,
609620
const FieldDescriptor* field) {
610621

622+
// backported from 3.8.0
623+
if (--recursion_limit_ < 0) {
624+
ReportError("Message is too deep");
625+
return false;
626+
}
627+
611628
// If the parse information tree is not NULL, create a nested one
612629
// for the nested message.
613630
ParseInfoTree* parent = parse_info_tree_;
@@ -624,18 +641,27 @@ class TextFormat::Parser::ParserImpl {
624641
delimiter));
625642
}
626643

644+
// backported from 3.8.0
645+
++recursion_limit_;
646+
627647
// Reset the parse information tree.
628648
parse_info_tree_ = parent;
629649
return true;
630650
}
631651

632652
// Skips the whole body of a message including the beginning delimiter and
633653
// the ending delimiter.
634-
bool SkipFieldMessage(UnknownFieldSet* unknown_fields) {
654+
bool SkipFieldMessage(UnknownFieldSet* unknown_fields, int recursion_limit) {
655+
// OpenCV specific
656+
if (--recursion_limit < 0) {
657+
ReportError("Message is too deep (SkipFieldMessage)");
658+
return false;
659+
}
660+
635661
string delimiter;
636662
DO(ConsumeMessageDelimiter(&delimiter));
637663
while (!LookingAt(">") && !LookingAt("}")) {
638-
DO(SkipField(unknown_fields));
664+
DO(SkipField(unknown_fields, recursion_limit));
639665
}
640666
DO(Consume(delimiter));
641667
return true;
@@ -775,7 +801,14 @@ class TextFormat::Parser::ParserImpl {
775801
return true;
776802
}
777803

778-
bool SkipFieldValue(UnknownFieldSet* unknown_field) {
804+
bool SkipFieldValue(UnknownFieldSet* unknown_field, int recursion_limit) {
805+
806+
// OpenCV specific
807+
if (--recursion_limit < 0) {
808+
ReportError("Message is too deep (SkipFieldValue)");
809+
return false;
810+
}
811+
779812
if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
780813
while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
781814
tokenizer_.Next();
@@ -785,9 +818,9 @@ class TextFormat::Parser::ParserImpl {
785818
if (TryConsume("[")) {
786819
while (true) {
787820
if (!LookingAt("{") && !LookingAt("<")) {
788-
DO(SkipFieldValue(unknown_field));
821+
DO(SkipFieldValue(unknown_field, recursion_limit));
789822
} else {
790-
DO(SkipFieldMessage(unknown_field));
823+
DO(SkipFieldMessage(unknown_field, recursion_limit));
791824
}
792825
if (TryConsume("]")) {
793826
break;
@@ -1156,6 +1189,7 @@ class TextFormat::Parser::ParserImpl {
11561189
const bool allow_field_number_;
11571190
const bool allow_partial_;
11581191
bool had_errors_;
1192+
int recursion_limit_; // backported from 3.8.0
11591193
};
11601194

11611195
#undef DO
@@ -1306,17 +1340,19 @@ class TextFormat::Printer::TextGenerator
13061340
TextFormat::Finder::~Finder() {
13071341
}
13081342

1309-
TextFormat::Parser::Parser(bool allow_unknown_field)
1343+
TextFormat::Parser::Parser()
13101344
: error_collector_(NULL),
13111345
finder_(NULL),
13121346
parse_info_tree_(NULL),
13131347
allow_partial_(false),
13141348
allow_case_insensitive_field_(false),
1315-
allow_unknown_field_(allow_unknown_field),
1349+
allow_unknown_field_(false),
13161350
allow_unknown_enum_(false),
13171351
allow_field_number_(false),
13181352
allow_relaxed_whitespace_(false),
1319-
allow_singular_overwrites_(false) {
1353+
allow_singular_overwrites_(false),
1354+
recursion_limit_(std::numeric_limits<int>::max())
1355+
{
13201356
}
13211357

13221358
TextFormat::Parser::~Parser() {}
@@ -1335,7 +1371,7 @@ bool TextFormat::Parser::Parse(io::ZeroCopyInputStream* input,
13351371
overwrites_policy,
13361372
allow_case_insensitive_field_, allow_unknown_field_,
13371373
allow_unknown_enum_, allow_field_number_,
1338-
allow_relaxed_whitespace_, allow_partial_);
1374+
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
13391375
return MergeUsingImpl(input, output, &parser);
13401376
}
13411377

@@ -1353,7 +1389,7 @@ bool TextFormat::Parser::Merge(io::ZeroCopyInputStream* input,
13531389
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
13541390
allow_case_insensitive_field_, allow_unknown_field_,
13551391
allow_unknown_enum_, allow_field_number_,
1356-
allow_relaxed_whitespace_, allow_partial_);
1392+
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
13571393
return MergeUsingImpl(input, output, &parser);
13581394
}
13591395

@@ -1388,7 +1424,7 @@ bool TextFormat::Parser::ParseFieldValueFromString(
13881424
ParserImpl::ALLOW_SINGULAR_OVERWRITES,
13891425
allow_case_insensitive_field_, allow_unknown_field_,
13901426
allow_unknown_enum_, allow_field_number_,
1391-
allow_relaxed_whitespace_, allow_partial_);
1427+
allow_relaxed_whitespace_, allow_partial_, recursion_limit_);
13921428
return parser.ParseField(field, output);
13931429
}
13941430

3rdparty/protobuf/src/google/protobuf/text_format.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
457457
// For more control over parsing, use this class.
458458
class LIBPROTOBUF_EXPORT Parser {
459459
public:
460-
Parser(bool allow_unknown_field = false);
460+
Parser();
461461
~Parser();
462462

463463
// Like TextFormat::Parse().
@@ -508,10 +508,24 @@ class LIBPROTOBUF_EXPORT TextFormat {
508508
Message* output);
509509

510510

511+
// backported from 3.8.0
512+
// When an unknown field is met, parsing will fail if this option is set
513+
// to false(the default). If true, unknown fields will be ignored and
514+
// a warning message will be generated.
515+
// Please aware that set this option true may hide some errors (e.g.
516+
// spelling error on field name). Avoid to use this option if possible.
517+
void AllowUnknownField(bool allow) { allow_unknown_field_ = allow; }
518+
519+
511520
void AllowFieldNumber(bool allow) {
512521
allow_field_number_ = allow;
513522
}
514523

524+
// backported from 3.8.0
525+
// Sets maximum recursion depth which parser can use. This is effectively
526+
// the maximum allowed nesting of proto messages.
527+
void SetRecursionLimit(int limit) { recursion_limit_ = limit; }
528+
515529
private:
516530
// Forward declaration of an internal class used to parse text
517531
// representations (see text_format.cc for implementation).
@@ -533,6 +547,7 @@ class LIBPROTOBUF_EXPORT TextFormat {
533547
bool allow_field_number_;
534548
bool allow_relaxed_whitespace_;
535549
bool allow_singular_overwrites_;
550+
int recursion_limit_; // backported from 3.8.0
536551
};
537552

538553

modules/dnn/src/caffe/caffe_io.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,11 +1120,12 @@ bool ReadProtoFromTextFile(const char* filename, Message* proto) {
11201120
std::ifstream fs(filename, std::ifstream::in);
11211121
CHECK(fs.is_open()) << "Can't open \"" << filename << "\"";
11221122
IstreamInputStream input(&fs);
1123+
google::protobuf::TextFormat::Parser parser;
11231124
#ifndef OPENCV_DNN_EXTERNAL_PROTOBUF
1124-
return google::protobuf::TextFormat::Parser(true).Parse(&input, proto);
1125-
#else
1126-
return google::protobuf::TextFormat::Parser().Parse(&input, proto);
1125+
parser.AllowUnknownField(true);
1126+
parser.SetRecursionLimit(1000);
11271127
#endif
1128+
return parser.Parse(&input, proto);
11281129
}
11291130

11301131
bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
@@ -1137,12 +1138,12 @@ bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
11371138

11381139
bool ReadProtoFromTextBuffer(const char* data, size_t len, Message* proto) {
11391140
ArrayInputStream input(data, len);
1141+
google::protobuf::TextFormat::Parser parser;
11401142
#ifndef OPENCV_DNN_EXTERNAL_PROTOBUF
1141-
return google::protobuf::TextFormat::Parser(true).Parse(&input, proto);
1142-
#else
1143-
return google::protobuf::TextFormat::Parser().Parse(&input, proto);
1143+
parser.AllowUnknownField(true);
1144+
parser.SetRecursionLimit(1000);
11441145
#endif
1145-
1146+
return parser.Parse(&input, proto);
11461147
}
11471148

11481149

0 commit comments

Comments
 (0)