@@ -183,14 +183,26 @@ def _get_string(data, position, obj_end, opts, dummy):
183183 opts .unicode_decode_error_handler , True )[0 ], end + 1
184184
185185
186- def _get_object (data , position , obj_end , opts , dummy ):
187- """Decode a BSON subdocument to opts.document_class or bson.dbref.DBRef."""
188- obj_size = _UNPACK_INT (data [position :position + 4 ])[0 ]
186+ def _get_object_size (data , position , obj_end ):
187+ """Validate and return a BSON document's size."""
188+ try :
189+ obj_size = _UNPACK_INT (data [position :position + 4 ])[0 ]
190+ except struct .error as exc :
191+ raise InvalidBSON (str (exc ))
189192 end = position + obj_size - 1
190- if data [end :position + obj_size ] != b"\x00 " :
193+ if data [end :end + 1 ] != b"\x00 " :
191194 raise InvalidBSON ("bad eoo" )
192195 if end >= obj_end :
193196 raise InvalidBSON ("invalid object length" )
197+ # If this is the top-level document, validate the total size too.
198+ if position == 0 and obj_size != obj_end :
199+ raise InvalidBSON ("invalid object length" )
200+ return obj_size , end
201+
202+
203+ def _get_object (data , position , obj_end , opts , dummy ):
204+ """Decode a BSON subdocument to opts.document_class or bson.dbref.DBRef."""
205+ obj_size , end = _get_object_size (data , position , obj_end )
194206 if _raw_document_class (opts .document_class ):
195207 return (opts .document_class (data [position :end + 1 ], opts ),
196208 position + obj_size )
@@ -406,38 +418,26 @@ def _element_to_dict(data, position, obj_end, opts):
406418 _element_to_dict = _cbson ._element_to_dict
407419
408420
409- def _iterate_elements (data , position , obj_end , opts ):
421+ def _elements_to_dict (data , position , obj_end , opts , result = None ):
422+ """Decode a BSON document into result."""
423+ if result is None :
424+ result = opts .document_class ()
410425 end = obj_end - 1
411426 while position < end :
412- (key , value , position ) = _element_to_dict (data , position , obj_end , opts )
413- yield key , value , position
414-
415-
416- def _elements_to_dict (data , position , obj_end , opts ):
417- """Decode a BSON document."""
418- result = opts .document_class ()
419- pos = position
420- for key , value , pos in _iterate_elements (data , position , obj_end , opts ):
427+ key , value , position = _element_to_dict (data , position , obj_end , opts )
421428 result [key ] = value
422- if pos != obj_end :
429+ if position != obj_end :
423430 raise InvalidBSON ('bad object or element length' )
424431 return result
425432
426433
427434def _bson_to_dict (data , opts ):
428435 """Decode a BSON string to document_class."""
429- try :
430- obj_size = _UNPACK_INT (data [:4 ])[0 ]
431- except struct .error as exc :
432- raise InvalidBSON (str (exc ))
433- if obj_size != len (data ):
434- raise InvalidBSON ("invalid object size" )
435- if data [obj_size - 1 :obj_size ] != b"\x00 " :
436- raise InvalidBSON ("bad eoo" )
437436 try :
438437 if _raw_document_class (opts .document_class ):
439438 return opts .document_class (data , opts )
440- return _elements_to_dict (data , 4 , obj_size - 1 , opts )
439+ _ , end = _get_object_size (data , 0 , len (data ))
440+ return _elements_to_dict (data , 4 , end , opts )
441441 except InvalidBSON :
442442 raise
443443 except Exception :
0 commit comments