cpython: a2688e252204 (original) (raw)
Mercurial > cpython
changeset 70451:a2688e252204 3.1
Issue #985064: Make plistlib more resilient to faulty input plists. Patch by Mher Movsisyan. [#985064]
Ned Deily nad@acm.org | |
---|---|
date | Sat, 28 May 2011 02:19:19 -0700 |
parents | 0cded2f2cea3 |
children | f555d959a5d7 bd49031b9488 |
files | Lib/plistlib.py Lib/test/test_plistlib.py Misc/ACKS Misc/NEWS |
diffstat | 4 files changed, 67 insertions(+), 22 deletions(-)[+] [-] Lib/plistlib.py 59 Lib/test/test_plistlib.py 26 Misc/ACKS 1 Misc/NEWS 3 |
line wrap: on
line diff
--- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -68,13 +68,15 @@ def readPlist(pathOrFile): usually is a dictionary). """ didOpen = False
- if isinstance(pathOrFile, str):
pathOrFile = open(pathOrFile, 'rb')[](#l1.8)
didOpen = True[](#l1.9)
- p = PlistParser()
- rootObject = p.parse(pathOrFile)
- if didOpen:
pathOrFile.close()[](#l1.13)
- try:
if isinstance(pathOrFile, str):[](#l1.15)
pathOrFile = open(pathOrFile, 'rb')[](#l1.16)
didOpen = True[](#l1.17)
p = PlistParser()[](#l1.18)
rootObject = p.parse(pathOrFile)[](#l1.19)
- finally:
if didOpen:[](#l1.21)
return rootObject @@ -83,15 +85,17 @@ def writePlist(rootObject, pathOrFile): file name or a (writable) file object. """ didOpen = FalsepathOrFile.close()[](#l1.22)
- if isinstance(pathOrFile, str):
pathOrFile = open(pathOrFile, 'wb')[](#l1.31)
didOpen = True[](#l1.32)
- writer = PlistWriter(pathOrFile)
- writer.writeln("<plist version="1.0">")
- writer.writeValue(rootObject)
- writer.writeln("")
- if didOpen:
pathOrFile.close()[](#l1.38)
- try:
if isinstance(pathOrFile, str):[](#l1.40)
pathOrFile = open(pathOrFile, 'wb')[](#l1.41)
didOpen = True[](#l1.42)
writer = PlistWriter(pathOrFile)[](#l1.43)
writer.writeln("<plist version=\"1.0\">")[](#l1.44)
writer.writeValue(rootObject)[](#l1.45)
writer.writeln("</plist>")[](#l1.46)
- finally:
if didOpen:[](#l1.48)
pathOrFile.close()[](#l1.49)
def readPlistFromBytes(data): @@ -352,7 +356,6 @@ class Data: def repr(self): return "%s(%s)" % (self.class.name, repr(self.data)) - class PlistParser: def init(self): @@ -362,11 +365,11 @@ class PlistParser: def parse(self, fileobj): from xml.parsers.expat import ParserCreate
parser = ParserCreate()[](#l1.65)
parser.StartElementHandler = self.handleBeginElement[](#l1.66)
parser.EndElementHandler = self.handleEndElement[](#l1.67)
parser.CharacterDataHandler = self.handleData[](#l1.68)
parser.ParseFile(fileobj)[](#l1.69)
self.parser = ParserCreate()[](#l1.70)
self.parser.StartElementHandler = self.handleBeginElement[](#l1.71)
self.parser.EndElementHandler = self.handleEndElement[](#l1.72)
self.parser.CharacterDataHandler = self.handleData[](#l1.73)
self.parser.ParseFile(fileobj)[](#l1.74) return self.root[](#l1.75)
def handleBeginElement(self, element, attrs): @@ -385,12 +388,18 @@ class PlistParser: def addObject(self, value): if self.currentKey is not None:
if not isinstance(self.stack[-1], type({})):[](#l1.82)
raise ValueError("unexpected element at line %d" %[](#l1.83)
self.parser.CurrentLineNumber)[](#l1.84) self.stack[-1][self.currentKey] = value[](#l1.85) self.currentKey = None[](#l1.86) elif not self.stack:[](#l1.87) # this is the root object[](#l1.88) self.root = value[](#l1.89) else:[](#l1.90)
if not isinstance(self.stack[-1], type([])):[](#l1.91)
raise ValueError("unexpected element at line %d" %[](#l1.92)
self.parser.CurrentLineNumber)[](#l1.93) self.stack[-1].append(value)[](#l1.94)
def getData(self): @@ -405,9 +414,15 @@ class PlistParser: self.addObject(d) self.stack.append(d) def end_dict(self):
if self.currentKey:[](#l1.101)
raise ValueError("missing value for key '%s' at line %d" %[](#l1.102)
(self.currentKey,self.parser.CurrentLineNumber))[](#l1.103) self.stack.pop()[](#l1.104)
if self.currentKey or not isinstance(self.stack[-1], type({})):[](#l1.107)
raise ValueError("unexpected key at line %d" %[](#l1.108)
self.parser.CurrentLineNumber)[](#l1.109) self.currentKey = self.getData()[](#l1.110)
--- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -175,6 +175,32 @@ class TestPlistlib(unittest.TestCase): self.assertEqual(test1, result1) self.assertEqual(test2, result2)
- def test_invalidarray(self):
for i in ["<key>key inside an array</key>",[](#l2.8)
"<key>key inside an array2</key><real>3</real>",[](#l2.9)
"<true/><key>key inside an array3</key>"]:[](#l2.10)
self.assertRaises(ValueError, plistlib.readPlistFromBytes,[](#l2.11)
("<plist><array>%s</array></plist>"%i).encode())[](#l2.12)
- def test_invaliddict(self):
for i in ["<key><true/>k</key><string>compound key</string>",[](#l2.15)
"<key>single key</key>",[](#l2.16)
"<string>missing key</string>",[](#l2.17)
"<key>k1</key><string>v1</string><real>5.3</real>"[](#l2.18)
"<key>k1</key><key>k2</key><string>double key</string>"]:[](#l2.19)
self.assertRaises(ValueError, plistlib.readPlistFromBytes,[](#l2.20)
("<plist><dict>%s</dict></plist>"%i).encode())[](#l2.21)
self.assertRaises(ValueError, plistlib.readPlistFromBytes,[](#l2.22)
("<plist><array><dict>%s</dict></array></plist>"%i).encode())[](#l2.23)
- def test_invalidinteger(self):
self.assertRaises(ValueError, plistlib.readPlistFromBytes,[](#l2.26)
b"<plist><integer>not integer</integer></plist>")[](#l2.27)
- def test_invalidreal(self):
self.assertRaises(ValueError, plistlib.readPlistFromBytes,[](#l2.30)
b"<plist><integer>not real</integer></plist>")[](#l2.31)
+ def test_main(): support.run_unittest(TestPlistlib)
--- a/Misc/ACKS +++ b/Misc/ACKS @@ -563,6 +563,7 @@ Skip Montanaro Paul Moore Derek Morr James A Morrison +Mher Movsisyan Sjoerd Mullender Sape Mullender Michael Muller
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -80,6 +80,9 @@ Core and Builtins Library ------- +- Issue #985064: Make plistlib more resilient to faulty input plists.