summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Samuels <richard.samuels@mongodb.com>2020-07-08 16:49:12 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-14 18:55:02 +0000
commiteb6dc1da7ce35cf005b20c2933108341f7dee1a7 (patch)
tree981737ea92f0a31c93fe9d6330c8d44b4e43314d
parentf1d1e28bb59cfdda58c9bf8aaf50561eca3aea4d (diff)
downloadmongo-eb6dc1da7ce35cf005b20c2933108341f7dee1a7.tar.gz
SERVER-43055 Prevent an exception when gdb prints a BSONObj with datetimes beyond datetime.MAXYEAR
-rw-r--r--buildscripts/gdb/mongo_printers.py32
1 files changed, 25 insertions, 7 deletions
diff --git a/buildscripts/gdb/mongo_printers.py b/buildscripts/gdb/mongo_printers.py
index 92cbef3aacf..6adf0f3b3b0 100644
--- a/buildscripts/gdb/mongo_printers.py
+++ b/buildscripts/gdb/mongo_printers.py
@@ -104,14 +104,20 @@ class BSONObjPrinter(object):
"""Initialize BSONObjPrinter."""
self.val = val
self.ptr = self.val['_objdata'].cast(gdb.lookup_type('void').pointer())
+ self.is_valid = False
+
# Handle the endianness of the BSON object size, which is represented as a 32-bit integer
# in little-endian format.
inferior = gdb.selected_inferior()
if self.ptr.is_optimized_out:
# If the value has been optimized out, we cannot decode it.
self.size = -1
+ self.raw_memory = None
else:
self.size = struct.unpack('<I', inferior.read_memory(self.ptr, 4))[0]
+ self.raw_memory = bytes(memoryview(inferior.read_memory(self.ptr, self.size)))
+ if bson:
+ self.is_valid = bson.is_valid(self.raw_memory)
@staticmethod
def display_hint():
@@ -120,14 +126,13 @@ class BSONObjPrinter(object):
def children(self):
"""Children."""
- # Do not decode a BSONObj with an invalid size.
- if not bson or self.size < 5 or self.size > 17 * 1024 * 1024:
+ # Do not decode a BSONObj with an invalid size, or that is considered
+ # invalid by pymongo.
+ if not bson or not self.is_valid or self.size < 5 or self.size > 17 * 1024 * 1024:
return
- inferior = gdb.selected_inferior()
- buf = bson.BSON(bytes(inferior.read_memory(self.ptr, self.size)))
options = CodecOptions(document_class=collections.OrderedDict)
- bsondoc = buf.decode(codec_options=options)
+ bsondoc = bson.decode(self.raw_memory, codec_options=options)
for key, val in list(bsondoc.items()):
yield 'key', key
@@ -137,7 +142,7 @@ class BSONObjPrinter(object):
"""Return BSONObj for printing."""
# The value has been optimized out.
if self.size == -1:
- return "BSONObj @ %s" % (self.ptr)
+ return "BSONObj @ %s - optimized out" % (self.ptr)
ownership = "owned" if self.val['_ownedBuffer']['_buffer']['_holder']['px'] else "unowned"
@@ -148,7 +153,20 @@ class BSONObjPrinter(object):
if size == 5:
return "%s empty BSONObj @ %s" % (ownership, self.ptr)
- return "%s BSONObj %s bytes @ %s" % (ownership, size, self.ptr)
+
+ suffix = ""
+ if not self.is_valid:
+ # Wondering why this is unprintable? See PYTHON-1824. The Python
+ # driver's BSON implementation does not support all possible BSON
+ # datetimes. (specifically any BSON datetime where the year is >
+ # datetime.MAXYEAR (usually 9999)).
+ # Attempting to print any BSONObj that contains an out of range
+ # datetime at any level of the document will cause an exception.
+ # There exists no workaround for this in the driver; not even the
+ # TypeDecoder API works for this because the BSON implementation
+ # errors out early when the date is out of range.
+ suffix = " - unprintable or invalid"
+ return "%s BSONObj %s bytes @ %s%s" % (ownership, size, self.ptr, suffix)
class UUIDPrinter(object):