Hello community,

here is the log from the commit of package python-biplist for openSUSE:Factory 
checked in at 2018-05-23 16:09:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-biplist (Old)
 and      /work/SRC/openSUSE:Factory/.python-biplist.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-biplist"

Wed May 23 16:09:18 2018 rev:11 rq:611233 version:1.0.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-biplist/python-biplist.changes    
2017-09-04 12:31:31.036051169 +0200
+++ /work/SRC/openSUSE:Factory/.python-biplist.new/python-biplist.changes       
2018-05-23 16:09:39.796748386 +0200
@@ -1,0 +2,12 @@
+Tue May 22 12:18:24 UTC 2018 - [email protected]
+
+- Disable one test that expect int to be equal to long on 32bit
+
+-------------------------------------------------------------------
+Tue May 22 12:13:16 UTC 2018 - [email protected]
+
+- Update to version 1.0.3:
+  * Added additional checks to guard against invalid plists. This includes 
writing and reading plists with recursive collections.
+  * Handle OverflowErrors when reading dates outside the range of 
datetime.datetime
+
+-------------------------------------------------------------------

Old:
----
  biplist-1.0.2.tar.gz

New:
----
  biplist-1.0.3.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-biplist.spec ++++++
--- /var/tmp/diff_new_pack.dufPJ1/_old  2018-05-23 16:09:40.456724216 +0200
+++ /var/tmp/diff_new_pack.dufPJ1/_new  2018-05-23 16:09:40.464723923 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-biplist
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -15,29 +15,22 @@
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
-%ifarch x86_64
-%bcond_without  test
-%else
-%bcond_with     test
-%endif
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-biplist
-Version:        1.0.2
+Version:        1.0.3
 Release:        0
 Summary:        A library for reading/writing binary plists
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
-Url:            https://bitbucket.org/wooster/biplist
+URL:            https://bitbucket.org/wooster/biplist
 Source:         
https://files.pythonhosted.org/packages/source/b/biplist/biplist-%{version}.tar.gz
+BuildRequires:  %{python_module coverage}
 BuildRequires:  %{python_module devel}
+BuildRequires:  %{python_module nose}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
-%if %{with test}
-BuildRequires:  %{python_module coverage}
-BuildRequires:  %{python_module nose}
-%endif
 BuildArch:      noarch
 %python_subpackages
 
@@ -58,14 +51,13 @@
 %python_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
-%if %{with test}
 %check
-%python_exec setup.py test
-%endif
+# Test on 32bit expects long==int which is true only on py3
+%python_expand nosetests-%{$python_bin_suffix} -e testIntBoundaries
 
 %files %{python_files}
-%defattr(-,root,root,-)
-%doc AUTHORS LICENSE README.md
+%license LICENSE
+%doc AUTHORS README.md
 %{python_sitelib}/*
 
 %changelog

++++++ biplist-1.0.2.tar.gz -> biplist-1.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/PKG-INFO new/biplist-1.0.3/PKG-INFO
--- old/biplist-1.0.2/PKG-INFO  2017-05-11 01:02:57.000000000 +0200
+++ new/biplist-1.0.3/PKG-INFO  2017-12-04 00:36:36.000000000 +0100
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: biplist
-Version: 1.0.2
+Version: 1.0.3
 Summary: biplist is a library for reading/writing binary plists.
 Home-page: https://bitbucket.org/wooster/biplist
 Author: Andrew Wooster
 Author-email: [email protected]
 License: BSD
-Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.2.tar.gz
+Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.3.tar.gz
 Description: `biplist` is a binary plist parser/generator for Python.
         
         Binary Property List (plist) files provide a faster and smaller 
serialization
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/biplist/__init__.py 
new/biplist-1.0.3/biplist/__init__.py
--- old/biplist-1.0.2/biplist/__init__.py       2017-05-11 00:53:56.000000000 
+0200
+++ new/biplist-1.0.3/biplist/__init__.py       2017-12-04 00:34:32.000000000 
+0100
@@ -222,6 +222,8 @@
     offsets = None
     trailer = None
     currentOffset = 0
+    # Used to detect recursive object references.
+    offsetsStack = []
     
     def __init__(self, fileOrStream):
         """Raises NotBinaryPlistException."""
@@ -236,6 +238,7 @@
         self.contents = ''
         self.offsets = []
         self.currentOffset = 0
+        self.offsetsStack = []
     
     def readRoot(self):
         result = None
@@ -250,13 +253,44 @@
         trailerContents = self.contents[-32:]
         try:
             self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", 
trailerContents))
+            
+            if pow(2, self.trailer.offsetSize*8) < 
self.trailer.offsetTableOffset:
+                raise InvalidPlistException("Offset size insufficient to 
reference all objects.")
+            
+            if pow(2, self.trailer.objectRefSize*8) < self.trailer.offsetCount:
+                raise InvalidPlistException("Too many offsets to represent in 
size of object reference representation.")
+            
             offset_size = self.trailer.offsetSize * self.trailer.offsetCount
             offset = self.trailer.offsetTableOffset
+            
+            if offset + offset_size > pow(2, 64):
+                raise InvalidPlistException("Offset table is excessively 
long.")
+            
+            if self.trailer.offsetSize > 16:
+                raise InvalidPlistException("Offset size is greater than 
maximum integer size.")
+            
+            if self.trailer.objectRefSize == 0:
+                raise InvalidPlistException("Object reference size is zero.")
+            
+            if offset >= len(self.contents) - 32:
+                raise InvalidPlistException("Offset table offset is too 
large.")
+            
+            if offset < len("bplist00x"):
+                raise InvalidPlistException("Offset table offset is too 
small.")
+            
+            if self.trailer.topLevelObjectNumber >= self.trailer.offsetCount:
+                raise InvalidPlistException("Top level object number is larger 
than the number of objects.")
+            
             offset_contents = self.contents[offset:offset+offset_size]
             offset_i = 0
+            offset_table_length = len(offset_contents)
+            
             while offset_i < self.trailer.offsetCount:
                 begin = self.trailer.offsetSize*offset_i
-                tmp_contents = 
offset_contents[begin:begin+self.trailer.offsetSize]
+                end = begin+self.trailer.offsetSize
+                if end > offset_table_length:
+                    raise InvalidPlistException("End of object is at invalid 
offset %d in offset table of length %d" % (end, offset_table_length))
+                tmp_contents = offset_contents[begin:end]
                 tmp_sized = self.getSizedInteger(tmp_contents, 
self.trailer.offsetSize)
                 self.offsets.append(tmp_sized)
                 offset_i += 1
@@ -267,11 +301,29 @@
         return result
     
     def setCurrentOffsetToObjectNumber(self, objectNumber):
+        if objectNumber > len(self.offsets) - 1:
+            raise InvalidPlistException("Invalid offset number: %d" % 
objectNumber)
         self.currentOffset = self.offsets[objectNumber]
+        if self.currentOffset in self.offsetsStack:
+            raise InvalidPlistException("Recursive data structure detected in 
object: %d" % objectNumber)
+    
+    def beginOffsetProtection(self):
+        self.offsetsStack.append(self.currentOffset)
+        return self.currentOffset
+    
+    def endOffsetProtection(self, offset):
+        try:
+            index = self.offsetsStack.index(offset)
+            self.offsetsStack = self.offsetsStack[:index]
+        except ValueError as e:
+            pass
     
     def readObject(self):
+        protection = self.beginOffsetProtection()
         result = None
         tmp_byte = self.contents[self.currentOffset:self.currentOffset+1]
+        if len(tmp_byte) != 1:
+            raise InvalidPlistException("No object found at offset: %d" % 
self.currentOffset)
         marker_byte = unpack("!B", tmp_byte)[0]
         format = (marker_byte >> 4) & 0x0f
         extra = marker_byte & 0x0f
@@ -279,7 +331,6 @@
         
         def proc_extra(extra):
             if extra == 0b1111:
-                #self.currentOffset += 1
                 extra = self.readObject()
             return extra
         
@@ -297,11 +348,9 @@
                 raise InvalidPlistException("Invalid object found at offset: 
%d" % (self.currentOffset - 1))
         # int
         elif format == 0b0001:
-            extra = proc_extra(extra)
             result = self.readInteger(pow(2, extra))
         # real
         elif format == 0b0010:
-            extra = proc_extra(extra)
             result = self.readReal(extra)
         # date
         elif format == 0b0011 and extra == 0b0011:
@@ -335,33 +384,39 @@
             result = self.readDict(extra)
         else:    
             raise InvalidPlistException("Invalid object found: {format: %s, 
extra: %s}" % (bin(format), bin(extra)))
+        self.endOffsetProtection(protection)
         return result
     
+    def readContents(self, length, description="Object contents"):
+        end = self.currentOffset + length
+        if end >= len(self.contents) - 32:
+            raise InvalidPlistException("%s extends into trailer" % 
description)
+        elif length < 0:
+            raise InvalidPlistException("%s length is less than zero" % length)
+        data = self.contents[self.currentOffset:end]
+        return data
+    
     def readInteger(self, byteSize):
-        result = 0
-        original_offset = self.currentOffset
-        data = self.contents[self.currentOffset:self.currentOffset + byteSize]
-        result = self.getSizedInteger(data, byteSize, as_number=True)
-        self.currentOffset = original_offset + byteSize
-        return result
+        data = self.readContents(byteSize, "Integer")
+        self.currentOffset = self.currentOffset + byteSize
+        return self.getSizedInteger(data, byteSize, as_number=True)
     
     def readReal(self, length):
-        result = 0.0
         to_read = pow(2, length)
-        data = self.contents[self.currentOffset:self.currentOffset+to_read]
+        data = self.readContents(to_read, "Real")
         if length == 2: # 4 bytes
             result = unpack('>f', data)[0]
         elif length == 3: # 8 bytes
             result = unpack('>d', data)[0]
         else:
-            raise InvalidPlistException("Unknown real of length %d bytes" % 
to_read)
+            raise InvalidPlistException("Unknown Real of length %d bytes" % 
to_read)
         return result
     
     def readRefs(self, count):    
         refs = []
         i = 0
         while i < count:
-            fragment = 
self.contents[self.currentOffset:self.currentOffset+self.trailer.objectRefSize]
+            fragment = self.readContents(self.trailer.objectRefSize, "Object 
reference")
             ref = self.getSizedInteger(fragment, len(fragment))
             refs.append(ref)
             self.currentOffset += self.trailer.objectRefSize
@@ -369,6 +424,8 @@
         return refs
     
     def readArray(self, count):
+        if not isinstance(count, (int, long)):
+            raise InvalidPlistException("Count of entries in dict isn't of 
integer type.")
         result = []
         values = self.readRefs(count)
         i = 0
@@ -380,6 +437,8 @@
         return result
     
     def readDict(self, count):
+        if not isinstance(count, (int, long)):
+            raise InvalidPlistException("Count of keys/values in dict isn't of 
integer type.")
         result = {}
         keys = self.readRefs(count)
         values = self.readRefs(count)
@@ -394,37 +453,56 @@
         return result
     
     def readAsciiString(self, length):
-        result = unpack("!%ds" % length, 
self.contents[self.currentOffset:self.currentOffset+length])[0]
+        if not isinstance(length, (int, long)):
+            raise InvalidPlistException("Length of ASCII string isn't of 
integer type.")
+        data = self.readContents(length, "ASCII string")
+        result = unpack("!%ds" % length, data)[0]
         self.currentOffset += length
         return str(result.decode('ascii'))
     
     def readUnicode(self, length):
+        if not isinstance(length, (int, long)):
+            raise InvalidPlistException("Length of Unicode string isn't of 
integer type.")
         actual_length = length*2
-        data = 
self.contents[self.currentOffset:self.currentOffset+actual_length]
-        # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0]
+        data = self.readContents(actual_length, "Unicode string")
         self.currentOffset += actual_length
         return data.decode('utf_16_be')
     
     def readDate(self):
-        result = unpack(">d", 
self.contents[self.currentOffset:self.currentOffset+8])[0]
+        data = self.readContents(8, "Date")
+        x = unpack(">d", data)[0]
+        if math.isnan(x):
+            raise InvalidPlistException("Date is NaN")
         # Use timedelta to workaround time_t size limitation on 32-bit python.
-        result = datetime.timedelta(seconds=result) + apple_reference_date
+        try:
+            result = datetime.timedelta(seconds=x) + apple_reference_date
+        except OverflowError:
+            if x > 0:
+                result = datetime.datetime.max
+            else:
+                result = datetime.datetime.min
         self.currentOffset += 8
         return result
     
     def readData(self, length):
-        result = self.contents[self.currentOffset:self.currentOffset+length]
+        if not isinstance(length, (int, long)):
+            raise InvalidPlistException("Length of data isn't of integer 
type.")
+        result = self.readContents(length, "Data")
         self.currentOffset += length
         return Data(result)
     
     def readUid(self, length):
+        if not isinstance(length, (int, long)):
+            raise InvalidPlistException("Uid length isn't of integer type.")
         return Uid(self.readInteger(length+1))
     
     def getSizedInteger(self, data, byteSize, as_number=False):
         """Numbers of 8 bytes are signed integers when they refer to numbers, 
but unsigned otherwise."""
         result = 0
+        if byteSize == 0:
+            raise InvalidPlistException("Encountered integer with byte size of 
0.")
         # 1, 2, and 4 byte integers are unsigned
-        if byteSize == 1:
+        elif byteSize == 1:
             result = unpack('>B', data)[0]
         elif byteSize == 2:
             result = unpack('>H', data)[0]
@@ -530,6 +608,8 @@
     referencePositions = None
     wrappedTrue = None
     wrappedFalse = None
+    # Used to detect recursive object references.
+    objectsStack = []
     
     def __init__(self, file):
         self.reset()
@@ -548,6 +628,8 @@
         # A dict of the positions of the written uniques.
         self.referencePositions = {}
         
+        self.objectsStack = []
+        
     def positionOfObjectReference(self, obj):
         """If the given object has been written already, return its
            position in the offset table. Otherwise, return None."""
@@ -588,39 +670,61 @@
         output = self.writeOffsetTable(output)
         output += pack('!xxxxxxBBQQQ', *self.trailer)
         self.file.write(output)
+    
+    def beginRecursionProtection(self, obj):
+        if not isinstance(obj, (set, dict, list, tuple)):
+            return
+        if id(obj) in self.objectsStack:
+            raise InvalidPlistException("Recursive containers are not allowed 
in plists.")
+        self.objectsStack.append(id(obj))
+    
+    def endRecursionProtection(self, obj):
+        if not isinstance(obj, (set, dict, list, tuple)):
+            return
+        try:
+            index = self.objectsStack.index(id(obj))
+            self.objectsStack = self.objectsStack[:index]
+        except ValueError as e:
+            pass
 
     def wrapRoot(self, root):
+        result = None
+        self.beginRecursionProtection(root)
+        
         if isinstance(root, bool):
             if root is True:
-                return self.wrappedTrue
+                result = self.wrappedTrue
             else:
-                return self.wrappedFalse
+                result = self.wrappedFalse
         elif isinstance(root, float):
-            return FloatWrapper(root)
+            result = FloatWrapper(root)
         elif isinstance(root, set):
             n = set()
             for value in root:
                 n.add(self.wrapRoot(value))
-            return HashableWrapper(n)
+            result = HashableWrapper(n)
         elif isinstance(root, dict):
             n = {}
             for key, value in iteritems(root):
                 n[self.wrapRoot(key)] = self.wrapRoot(value)
-            return HashableWrapper(n)
+            result = HashableWrapper(n)
         elif isinstance(root, list):
             n = []
             for value in root:
                 n.append(self.wrapRoot(value))
-            return HashableWrapper(n)
+            result = HashableWrapper(n)
         elif isinstance(root, tuple):
             n = tuple([self.wrapRoot(value) for value in root])
-            return HashableWrapper(n)
+            result = HashableWrapper(n)
         elif isinstance(root, (str, unicode)) and not isinstance(root, Data):
-            return StringWrapper(root)
+            result =  StringWrapper(root)
         elif isinstance(root, bytes):
-            return Data(root)
+            result = Data(root)
         else:
-            return root
+            result = root
+        
+        self.endRecursionProtection(root)
+        return result
 
     def incrementByteCount(self, field, incr=1):
         self.byteCounts = 
self.byteCounts._replace(**{field:self.byteCounts.__getattribute__(field) + 
incr})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/biplist.egg-info/PKG-INFO 
new/biplist-1.0.3/biplist.egg-info/PKG-INFO
--- old/biplist-1.0.2/biplist.egg-info/PKG-INFO 2017-05-11 01:02:57.000000000 
+0200
+++ new/biplist-1.0.3/biplist.egg-info/PKG-INFO 2017-12-04 00:36:36.000000000 
+0100
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: biplist
-Version: 1.0.2
+Version: 1.0.3
 Summary: biplist is a library for reading/writing binary plists.
 Home-page: https://bitbucket.org/wooster/biplist
 Author: Andrew Wooster
 Author-email: [email protected]
 License: BSD
-Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.2.tar.gz
+Download-URL: 
https://bitbucket.org/wooster/biplist/downloads/biplist-1.0.3.tar.gz
 Description: `biplist` is a binary plist parser/generator for Python.
         
         Binary Property List (plist) files provide a faster and smaller 
serialization
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/biplist.egg-info/SOURCES.txt 
new/biplist-1.0.3/biplist.egg-info/SOURCES.txt
--- old/biplist-1.0.2/biplist.egg-info/SOURCES.txt      2017-05-11 
01:02:57.000000000 +0200
+++ new/biplist-1.0.3/biplist.egg-info/SOURCES.txt      2017-12-04 
00:36:36.000000000 +0100
@@ -9,6 +9,7 @@
 biplist.egg-info/dependency_links.txt
 biplist.egg-info/not-zip-safe
 biplist.egg-info/top_level.txt
+tests/test_fuzz_results.py
 tests/test_invalid.py
 tests/test_utils.py
 tests/test_valid.py
@@ -19,9 +20,24 @@
 tests/data/bool_only_binary.plist
 tests/data/dict_only_binary.plist
 tests/data/empty_file.plist
+tests/data/invalid_object_offset_size.plist
+tests/data/invalid_object_ref_size.plist
 tests/data/large_int_limits.plist
 tests/data/nskeyedarchiver_example.plist
 tests/data/simple_binary.plist
+tests/data/small_date.plist
 tests/data/small_real.plist
 tests/data/unicode_empty.plist
-tests/data/unicode_root.plist
\ No newline at end of file
+tests/data/unicode_root.plist
+tests/fuzz_data/array_invalid_count.plist
+tests/fuzz_data/ascii_string_negative_length.plist
+tests/fuzz_data/ascii_string_too_long.plist
+tests/fuzz_data/date_seconds_is_nan.plist
+tests/fuzz_data/dictionary_invalid_count.plist
+tests/fuzz_data/integer_zero_byte_length.plist
+tests/fuzz_data/invalid_object_offset.plist
+tests/fuzz_data/invalid_offset_ending.plist
+tests/fuzz_data/list_index_out_of_range.plist
+tests/fuzz_data/no_marker_byte.plist
+tests/fuzz_data/real_invalid_length.plist
+tests/fuzz_data/recursive_object_offset.plist
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/setup.py new/biplist-1.0.3/setup.py
--- old/biplist-1.0.2/setup.py  2017-05-11 00:55:28.000000000 +0200
+++ new/biplist-1.0.3/setup.py  2017-12-03 23:18:14.000000000 +0100
@@ -19,7 +19,7 @@
 
 author = 'Andrew Wooster'
 email = '[email protected]'
-version = '1.0.2'
+version = '1.0.3'
 desc = 'biplist is a library for reading/writing binary plists.'
 
 setup(
Binary files old/biplist-1.0.2/tests/data/invalid_object_offset_size.plist and 
new/biplist-1.0.3/tests/data/invalid_object_offset_size.plist differ
Binary files old/biplist-1.0.2/tests/data/invalid_object_ref_size.plist and 
new/biplist-1.0.3/tests/data/invalid_object_ref_size.plist differ
Binary files old/biplist-1.0.2/tests/data/small_date.plist and 
new/biplist-1.0.3/tests/data/small_date.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/array_invalid_count.plist and 
new/biplist-1.0.3/tests/fuzz_data/array_invalid_count.plist differ
Binary files 
old/biplist-1.0.2/tests/fuzz_data/ascii_string_negative_length.plist and 
new/biplist-1.0.3/tests/fuzz_data/ascii_string_negative_length.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/ascii_string_too_long.plist and 
new/biplist-1.0.3/tests/fuzz_data/ascii_string_too_long.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/date_seconds_is_nan.plist and 
new/biplist-1.0.3/tests/fuzz_data/date_seconds_is_nan.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/dictionary_invalid_count.plist 
and new/biplist-1.0.3/tests/fuzz_data/dictionary_invalid_count.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/integer_zero_byte_length.plist 
and new/biplist-1.0.3/tests/fuzz_data/integer_zero_byte_length.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/invalid_object_offset.plist and 
new/biplist-1.0.3/tests/fuzz_data/invalid_object_offset.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/invalid_offset_ending.plist and 
new/biplist-1.0.3/tests/fuzz_data/invalid_offset_ending.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/list_index_out_of_range.plist 
and new/biplist-1.0.3/tests/fuzz_data/list_index_out_of_range.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/no_marker_byte.plist and 
new/biplist-1.0.3/tests/fuzz_data/no_marker_byte.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/real_invalid_length.plist and 
new/biplist-1.0.3/tests/fuzz_data/real_invalid_length.plist differ
Binary files old/biplist-1.0.2/tests/fuzz_data/recursive_object_offset.plist 
and new/biplist-1.0.3/tests/fuzz_data/recursive_object_offset.plist differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/tests/test_fuzz_results.py 
new/biplist-1.0.3/tests/test_fuzz_results.py
--- old/biplist-1.0.2/tests/test_fuzz_results.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/biplist-1.0.3/tests/test_fuzz_results.py        2017-12-03 
22:36:36.000000000 +0100
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+
+from biplist import *
+import os
+from test_utils import *
+import unittest
+
+class TestFuzzResults(unittest.TestCase):
+    def setUp(self):
+        pass
+    
+    def testCurrentOffsetOutOfRange(self):
+        try:
+            readPlist(fuzz_data_path('list_index_out_of_range.plist'))
+            self.fail("list index out of range, should fail")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidMarkerByteUnpack(self):
+        try:
+            readPlist(fuzz_data_path('no_marker_byte.plist'))
+            self.fail("No marker byte at object offset")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidObjectOffset(self):
+        try:
+            readPlist(fuzz_data_path('invalid_object_offset.plist'))
+            self.fail("Invalid object offset in offsets table")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testRecursiveObjectOffset(self):
+        try:
+            readPlist(fuzz_data_path('recursive_object_offset.plist'))
+            self.fail("Recursive object found")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testExcessivelyLongAsciiString(self):
+        try:
+            readPlist(fuzz_data_path('ascii_string_too_long.plist'))
+            self.fail("ASCII string extends into trailer")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testNegativelyLongAsciiString(self):
+        try:
+            readPlist(fuzz_data_path('ascii_string_negative_length.plist'))
+            self.fail("ASCII string length less than zero")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidOffsetEnding(self):
+        # The end of the offset is past the end of the offset table.
+        try:
+            readPlist(fuzz_data_path('invalid_offset_ending.plist'))
+            self.fail("End of offset after end of offset table")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidDictionaryObjectCount(self):
+        try:
+            readPlist(fuzz_data_path('dictionary_invalid_count.plist'))
+            self.fail("Dictionary object count is not of integer type")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidArrayObjectCount(self):
+        try:
+            readPlist(fuzz_data_path('array_invalid_count.plist'))
+            self.fail("Array object count is not of integer type")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidRealLength(self):
+        # We shouldn't have been checking for extra length reals, anyway.
+        try:
+            readPlist(fuzz_data_path('real_invalid_length.plist'))
+            self.fail("Real length is not of integer type")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testNaNDateSeconds(self):
+        try:
+            readPlist(fuzz_data_path('date_seconds_is_nan.plist'))
+            self.fail("Date seconds is NaN")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+    
+    def testIntegerWithZeroByteLength(self):
+        try:
+            readPlist(fuzz_data_path('integer_zero_byte_length.plist'))
+            self.fail("Integer has byte size of 0.")
+        except NotBinaryPlistException as e:
+            pass
+        except InvalidPlistException as e:
+            pass
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/tests/test_invalid.py 
new/biplist-1.0.3/tests/test_invalid.py
--- old/biplist-1.0.2/tests/test_invalid.py     2016-06-18 01:44:56.000000000 
+0200
+++ new/biplist-1.0.3/tests/test_invalid.py     2017-12-03 02:14:32.000000000 
+0100
@@ -1,8 +1,25 @@
+# -*- coding: utf-8 -*-
+
 from biplist import *
+from biplist import PlistTrailer
+from collections import namedtuple
+from math import pow
 import os
+from struct import pack
 from test_utils import *
 import unittest
 
+def trailerToString(trailer):
+    # Trailer is:
+    # 6 padding bytes
+    # 1 byte offsetSize
+    # 1 byte objectRefSize
+    # 8 bytes offsetCount (number of objects)
+    # 8 bytes topObjectNumber
+    # 8 bytes offsetTableOffset
+    # = 32 byte trailer
+    return pack('!xxxxxxBBQQQ', *trailer)
+
 class TestInvalidPlistFile(unittest.TestCase):
     def setUp(self):
         pass
@@ -28,6 +45,129 @@
             self.fail("Should not successfully read invalid plist.")
         except InvalidPlistException as e:
             pass
+    
+    def testInvalidTemplate(self):
+        # Test that our template plists for range tests are valid.
+        trailer = PlistTrailer(1, 1, 1, 0, 9)
+        contents = b''.join([b'bplist00', # header
+                             b'\x08',     # bool false
+                             b'\x08',     # object at offset 8
+                             trailerToString(trailer)
+                         ])
+        result = readPlistFromString(contents)
+        self.assertEqual(result, False)
+        
+        trailer = PlistTrailer(1, 1, 3, 0, 25)
+        contents = b''.join([b'bplist00bybiplist1.0', # header
+                             b'\xA2',     # array with two entries
+                             b'\x01',     # object entry 1
+                             b'\x02',     # object entry 2
+                             b'\x09',     # boolean false
+                             b'\x08',     # boolean true
+                             b'\x14',     # offset at 20
+                             b'\x17',     # offset at 23
+                             b'\x18',     # offset at 24
+                             trailerToString(trailer)
+                         ])
+        result = readPlistFromString(contents)
+        self.assertEqual(result, [True, False])
+    
+    def testInvalidOffsetSize(self):
+        # offset size can't be zero
+        try:
+            trailer = PlistTrailer(0, 1, 1, 0, 9)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Offset size can't be zero")
+        except InvalidPlistException as e:
+            pass
+        
+        # offset size can't be greater than 16
+        try:
+            trailer = PlistTrailer(17, 1, 1, 0, 9)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Offset size can't be greater than 16")
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidOffsetOverflow(self):
+        # The offsets can't overflow the number of bytes used to represent 
them.
+        try:
+            c = readPlist(data_path('invalid_object_offset_size.plist'))
+            self.fail("Object offset size too small to reference all objects")
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidObjectRefSize(self):
+        # object reference size can't be zero
+        try:
+            trailer = PlistTrailer(1, 0, 1, 0, 9)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Object reference size can't be zero")
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidObjectRefOverflow(self):
+        try:
+            readPlist(data_path('invalid_object_ref_size.plist'))
+            self.fail("Object ref size too small to reference all objects in 
the object table")
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidOffsestTableOffset(self):
+        # offsetTableOffset too large, extending into trailer
+        try:
+            trailer = PlistTrailer(1, 1, 1, 0, 10)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Should not read plist when offsetTableOffset is too 
large")
+        except InvalidPlistException as e:
+            pass
+        
+        # offsetTableOffset too small, extending into header or objects
+        try:
+            trailer = PlistTrailer(1, 1, 1, 0, 8)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Should not read plist when offsetTableOffset is too 
small")
+        except InvalidPlistException as e:
+            pass
+    
+    def testInvalidTopObjectNumber(self):
+        # topObjectNumber can't be greater than number of objects
+        try:
+            trailer = PlistTrailer(1, 1, 1, 1, 9)
+            contents = b''.join([b'bplist00', # header
+                                 b'\x08',     # bool false
+                                 b'\x08',     # object at offset 8
+                                 trailerToString(trailer)
+                             ])
+            readPlistFromString(contents)
+            self.fail("Top object number should not be greater than number of 
objects")
+        except InvalidPlistException as e:
+            pass
         
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/tests/test_utils.py 
new/biplist-1.0.3/tests/test_utils.py
--- old/biplist-1.0.2/tests/test_utils.py       2016-06-18 01:44:56.000000000 
+0200
+++ new/biplist-1.0.3/tests/test_utils.py       2017-12-03 21:29:16.000000000 
+0100
@@ -1,3 +1,5 @@
+# -*- coding: utf-8 -*-
+
 import os
 import subprocess
 import sys
@@ -5,6 +7,9 @@
 def data_path(path):
     return os.path.join(os.path.dirname(globals()["__file__"]), 'data', path)
 
+def fuzz_data_path(path):
+    return os.path.join(os.path.dirname(globals()["__file__"]), 'fuzz_data', 
path)
+
 def run_command(args, verbose = False):
     """Runs the command and returns the status and the output."""
     if verbose:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/tests/test_valid.py 
new/biplist-1.0.3/tests/test_valid.py
--- old/biplist-1.0.2/tests/test_valid.py       2016-06-18 01:44:56.000000000 
+0200
+++ new/biplist-1.0.3/tests/test_valid.py       2017-11-19 01:33:59.000000000 
+0100
@@ -57,6 +57,10 @@
         result = readPlist(data_path('unicode_empty.plist'))
         self.assertEqual(result, '')
     
+    def testBoolOnly(self):
+        result = readPlist(data_path('bool_only_binary.plist'))
+        self.assertEqual(result, False)
+    
     def testSmallReal(self):
         result = readPlist(data_path('small_real.plist'))
         self.assertEqual(result, {'4 byte real':0.5})
@@ -71,6 +75,11 @@
         result = readPlist(data_path("BFPersistentEventInfo.plist"))
         self.assertEqual(result['lastShownRatePromptDate'], 
datetime.datetime(1, 12, 30, 0, 0, 0))
 
+    def testSmallDates(self):
+        result = readPlist(data_path("small_date.plist"))
+        # Date stored in plist is 0000-12-30T00:00:00Z
+        self.assertEqual(result, {'MyDate': datetime.datetime(1, 1, 1, 0, 0)})
+
     def testKeyedArchiverPlist(self):
         """
         Archive is created with class like this:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/biplist-1.0.2/tests/test_write.py 
new/biplist-1.0.3/tests/test_write.py
--- old/biplist-1.0.2/tests/test_write.py       2016-06-18 01:44:56.000000000 
+0200
+++ new/biplist-1.0.3/tests/test_write.py       2017-12-04 00:35:04.000000000 
+0100
@@ -1,7 +1,12 @@
-#!/usr/local/env python
 # -*- coding: utf-8 -*-
 
-import datetime, io, os, subprocess, sys, tempfile, unittest
+import datetime
+import io
+import os
+import subprocess
+import sys
+import tempfile
+import unittest
 
 from biplist import *
 from biplist import PlistWriter
@@ -21,6 +26,8 @@
     xrange = range
 
 class TestWritePlist(unittest.TestCase):
+    def setUp(self):
+        pass
     
     def roundTrip(self, case, xml=False, expected=None, reprTest=True):
         # reprTest may fail randomly if True and the values being encoded 
include a dictionary with more
@@ -332,6 +339,20 @@
         self.roundTrip([Uid(1), 1])
         self.roundTrip([1, Uid(1)])
         self.roundTrip([Uid(1), Uid(1)])
+    
+    def testRecursiveWrite(self):
+        # Apple libraries disallow recursive containers, so we should fail on
+        # trying to write those.
+        root = []
+        child = [root]
+        root.extend(child)
+        try:
+            writePlistToString(root)
+            self.fail("Should not be able to write plists with recursive 
containers.")
+        except InvalidPlistException as e:
+            pass
+        except:
+            self.fail("Should get an invalid plist exception for recursive 
containers.")
 
 if __name__ == '__main__':
     unittest.main()


Reply via email to