Branch merge
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
index fbba791..fe622ad 100644
--- a/Lib/plistlib.py
+++ b/Lib/plistlib.py
@@ -68,13 +68,15 @@
     usually is a dictionary).
     """
     didOpen = False
-    if isinstance(pathOrFile, str):
-        pathOrFile = open(pathOrFile, 'rb')
-        didOpen = True
-    p = PlistParser()
-    rootObject = p.parse(pathOrFile)
-    if didOpen:
-        pathOrFile.close()
+    try:
+        if isinstance(pathOrFile, str):
+            pathOrFile = open(pathOrFile, 'rb')
+            didOpen = True
+        p = PlistParser()
+        rootObject = p.parse(pathOrFile)
+    finally:
+        if didOpen:
+            pathOrFile.close()
     return rootObject
 
 
@@ -83,15 +85,17 @@
     file name or a (writable) file object.
     """
     didOpen = False
-    if isinstance(pathOrFile, str):
-        pathOrFile = open(pathOrFile, 'wb')
-        didOpen = True
-    writer = PlistWriter(pathOrFile)
-    writer.writeln("<plist version=\"1.0\">")
-    writer.writeValue(rootObject)
-    writer.writeln("</plist>")
-    if didOpen:
-        pathOrFile.close()
+    try:
+        if isinstance(pathOrFile, str):
+            pathOrFile = open(pathOrFile, 'wb')
+            didOpen = True
+        writer = PlistWriter(pathOrFile)
+        writer.writeln("<plist version=\"1.0\">")
+        writer.writeValue(rootObject)
+        writer.writeln("</plist>")
+    finally:
+        if didOpen:
+            pathOrFile.close()
 
 
 def readPlistFromBytes(data):
@@ -352,7 +356,6 @@
     def __repr__(self):
         return "%s(%s)" % (self.__class__.__name__, repr(self.data))
 
-
 class PlistParser:
 
     def __init__(self):
@@ -362,11 +365,11 @@
 
     def parse(self, fileobj):
         from xml.parsers.expat import ParserCreate
-        parser = ParserCreate()
-        parser.StartElementHandler = self.handleBeginElement
-        parser.EndElementHandler = self.handleEndElement
-        parser.CharacterDataHandler = self.handleData
-        parser.ParseFile(fileobj)
+        self.parser = ParserCreate()
+        self.parser.StartElementHandler = self.handleBeginElement
+        self.parser.EndElementHandler = self.handleEndElement
+        self.parser.CharacterDataHandler = self.handleData
+        self.parser.ParseFile(fileobj)
         return self.root
 
     def handleBeginElement(self, element, attrs):
@@ -385,12 +388,18 @@
 
     def addObject(self, value):
         if self.currentKey is not None:
+            if not isinstance(self.stack[-1], type({})):
+                raise ValueError("unexpected element at line %d" %
+                                 self.parser.CurrentLineNumber)
             self.stack[-1][self.currentKey] = value
             self.currentKey = None
         elif not self.stack:
             # this is the root object
             self.root = value
         else:
+            if not isinstance(self.stack[-1], type([])):
+                raise ValueError("unexpected element at line %d" %
+                                 self.parser.CurrentLineNumber)
             self.stack[-1].append(value)
 
     def getData(self):
@@ -405,9 +414,15 @@
         self.addObject(d)
         self.stack.append(d)
     def end_dict(self):
+        if self.currentKey:
+            raise ValueError("missing value for key '%s' at line %d" %
+                             (self.currentKey,self.parser.CurrentLineNumber))
         self.stack.pop()
 
     def end_key(self):
+        if self.currentKey or not isinstance(self.stack[-1], type({})):
+            raise ValueError("unexpected key at line %d" %
+                             self.parser.CurrentLineNumber)
         self.currentKey = self.getData()
 
     def begin_array(self, attrs):
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
index b9a46b7..ccda920 100644
--- a/Lib/test/test_plistlib.py
+++ b/Lib/test/test_plistlib.py
@@ -175,6 +175,32 @@
         self.assertEqual(test1, result1)
         self.assertEqual(test2, result2)
 
+    def test_invalidarray(self):
+        for i in ["<key>key inside an array</key>",
+                  "<key>key inside an array2</key><real>3</real>",
+                  "<true/><key>key inside an array3</key>"]:
+            self.assertRaises(ValueError, plistlib.readPlistFromBytes,
+                              ("<plist><array>%s</array></plist>"%i).encode())
+
+    def test_invaliddict(self):
+        for i in ["<key><true/>k</key><string>compound key</string>",
+                  "<key>single key</key>",
+                  "<string>missing key</string>",
+                  "<key>k1</key><string>v1</string><real>5.3</real>"
+                  "<key>k1</key><key>k2</key><string>double key</string>"]:
+            self.assertRaises(ValueError, plistlib.readPlistFromBytes,
+                              ("<plist><dict>%s</dict></plist>"%i).encode())
+            self.assertRaises(ValueError, plistlib.readPlistFromBytes,
+                              ("<plist><array><dict>%s</dict></array></plist>"%i).encode())
+
+    def test_invalidinteger(self):
+        self.assertRaises(ValueError, plistlib.readPlistFromBytes,
+                          b"<plist><integer>not integer</integer></plist>")
+
+    def test_invalidreal(self):
+        self.assertRaises(ValueError, plistlib.readPlistFromBytes,
+                          b"<plist><integer>not real</integer></plist>")
+
 
 def test_main():
     support.run_unittest(TestPlistlib)
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index f977a7f..63ef7b9 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -673,6 +673,37 @@
 class BoundedSemaphoreTests(lock_tests.BoundedSemaphoreTests):
     semtype = staticmethod(threading.BoundedSemaphore)
 
+    @unittest.skipUnless(sys.platform == 'darwin', 'test macosx problem')
+    def test_recursion_limit(self):
+        # Issue 9670
+        # test that excessive recursion within a non-main thread causes
+        # an exception rather than crashing the interpreter on platforms
+        # like Mac OS X or FreeBSD which have small default stack sizes
+        # for threads
+        script = """if True:
+            import threading
+
+            def recurse():
+                return recurse()
+
+            def outer():
+                try:
+                    recurse()
+                except RuntimeError:
+                    pass
+
+            w = threading.Thread(target=outer)
+            w.start()
+            w.join()
+            print('end of main thread')
+            """
+        expected_output = "end of main thread\n"
+        p = subprocess.Popen([sys.executable, "-c", script],
+                             stdout=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        data = stdout.decode().replace('\r', '')
+        self.assertEqual(p.returncode, 0, "Unexpected error")
+        self.assertEqual(data, expected_output)
 
 def test_main():
     test.support.run_unittest(LockTests, RLockTests, EventTests,
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 270dfb4..ed1dc33 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -841,7 +841,7 @@
 XMLLIBSUBDIRS=  xml xml/dom xml/etree xml/parsers xml/sax
 LIBSUBDIRS=	tkinter tkinter/test tkinter/test/test_tkinter \
 		tkinter/test/test_ttk site-packages test test/data \
-		test/cjkencodings test/decimaltestdata \
+		test/cjkencodings test/decimaltestdata test/subprocessdata \
 		test/tracedmodules \
 		encodings \
 		email email/mime email/test email/test/data \
diff --git a/Misc/ACKS b/Misc/ACKS
index 80fda10..c698d73 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -563,6 +563,7 @@
 Paul Moore
 Derek Morr
 James A Morrison
+Mher Movsisyan
 Sjoerd Mullender
 Sape Mullender
 Michael Muller
diff --git a/Misc/NEWS b/Misc/NEWS
index 015018c..f04c643 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,11 @@
 Core and Builtins
 -----------------
 
+- Issue #9670: Increase the default stack size for secondary threads on
+  Mac OS X and FreeBSD to reduce the chances of a crash instead of a
+  "maximum recursion depth" RuntimeError exception.
+  (patch by Ronald Oussoren)
+
 - Correct lookup of __dir__ on objects. Among other things, this causes errors
   besides AttributeError found on lookup to be propagated.
 
@@ -75,6 +80,9 @@
 Library
 -------
 
+- Issue #985064: Make plistlib more resilient to faulty input plists.
+  Patch by Mher Movsisyan.
+
 - Issue #12175: RawIOBase.readall() now returns None if read() returns None.
 
 - Issue #12175: FileIO.readall() now raises a ValueError instead of an IOError
@@ -413,6 +421,8 @@
 Tests
 -----
 
+- Issue #12205: Fix test_subprocess failure due to uninstalled test data.
+
 - Issue #11614: import __hello__ prints "Hello World!". Patch written by
   Andreas Stührk.
 
diff --git a/Python/compile.c b/Python/compile.c
index 19b2add..0a85bf8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1977,7 +1977,7 @@
     compiler_use_next_block(c, except);
     for (i = 0; i < n; i++) {
         excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET(
-                                        s->v.TryExcept.handlers, i);
+            s->v.TryExcept.handlers, i);
         if (!handler->v.ExceptHandler.type && i < n-1)
             return compiler_error(c, "default 'except:' must be last");
         c->u->u_lineno_set = 0;
@@ -1993,70 +1993,70 @@
         }
         ADDOP(c, POP_TOP);
         if (handler->v.ExceptHandler.name) {
-        basicblock *cleanup_end, *cleanup_body;
+            basicblock *cleanup_end, *cleanup_body;
 
-        cleanup_end = compiler_new_block(c);
-        cleanup_body = compiler_new_block(c);
-        if(!(cleanup_end || cleanup_body))
-        return 0;
+            cleanup_end = compiler_new_block(c);
+            cleanup_body = compiler_new_block(c);
+            if (!(cleanup_end || cleanup_body))
+                return 0;
 
-        compiler_nameop(c, handler->v.ExceptHandler.name, Store);
-        ADDOP(c, POP_TOP);
+            compiler_nameop(c, handler->v.ExceptHandler.name, Store);
+            ADDOP(c, POP_TOP);
 
-        /*
-        try:
-            # body
-        except type as name:
-            try:
-            # body
-            finally:
-            name = None
-            del name
-        */
+            /*
+              try:
+              # body
+              except type as name:
+              try:
+              # body
+              finally:
+              name = None
+              del name
+            */
 
-        /* second try: */
-        ADDOP_JREL(c, SETUP_FINALLY, cleanup_end);
-        compiler_use_next_block(c, cleanup_body);
-        if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
-            return 0;
+            /* second try: */
+            ADDOP_JREL(c, SETUP_FINALLY, cleanup_end);
+            compiler_use_next_block(c, cleanup_body);
+            if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
+                return 0;
 
-        /* second # body */
-        VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
-        ADDOP(c, POP_BLOCK);
-        ADDOP(c, POP_EXCEPT);
-        compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
+            /* second # body */
+            VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
+            ADDOP(c, POP_BLOCK);
+            ADDOP(c, POP_EXCEPT);
+            compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
 
-        /* finally: */
-        ADDOP_O(c, LOAD_CONST, Py_None, consts);
-        compiler_use_next_block(c, cleanup_end);
-        if (!compiler_push_fblock(c, FINALLY_END, cleanup_end))
-            return 0;
+            /* finally: */
+            ADDOP_O(c, LOAD_CONST, Py_None, consts);
+            compiler_use_next_block(c, cleanup_end);
+            if (!compiler_push_fblock(c, FINALLY_END, cleanup_end))
+                return 0;
 
-        /* name = None */
-        ADDOP_O(c, LOAD_CONST, Py_None, consts);
-        compiler_nameop(c, handler->v.ExceptHandler.name, Store);
+            /* name = None */
+            ADDOP_O(c, LOAD_CONST, Py_None, consts);
+            compiler_nameop(c, handler->v.ExceptHandler.name, Store);
 
-        /* del name */
-        compiler_nameop(c, handler->v.ExceptHandler.name, Del);
+            /* del name */
+            compiler_nameop(c, handler->v.ExceptHandler.name, Del);
 
-        ADDOP(c, END_FINALLY);
-        compiler_pop_fblock(c, FINALLY_END, cleanup_end);
+            ADDOP(c, END_FINALLY);
+            compiler_pop_fblock(c, FINALLY_END, cleanup_end);
         }
         else {
-        basicblock *cleanup_body;
+            basicblock *cleanup_body;
 
-        cleanup_body = compiler_new_block(c);
-        if(!cleanup_body)
-        return 0;
+            cleanup_body = compiler_new_block(c);
+            if (!cleanup_body)
+                return 0;
 
             ADDOP(c, POP_TOP);
-        ADDOP(c, POP_TOP);
-        compiler_use_next_block(c, cleanup_body);
-        if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
-            return 0;
+            ADDOP(c, POP_TOP);
+            compiler_use_next_block(c, cleanup_body);
+            if (!compiler_push_fblock(c, FINALLY_TRY, cleanup_body))
+                return 0;
             VISIT_SEQ(c, stmt, handler->v.ExceptHandler.body);
-        ADDOP(c, POP_EXCEPT);
-        compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
+            ADDOP(c, POP_EXCEPT);
+            compiler_pop_fblock(c, FINALLY_TRY, cleanup_body);
         }
         ADDOP_JREL(c, JUMP_FORWARD, end);
         compiler_use_next_block(c, except);
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index 32fd2d0..244ebac 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -18,6 +18,18 @@
 #ifndef THREAD_STACK_SIZE
 #define THREAD_STACK_SIZE       0       /* use default stack size */
 #endif
+
+#if (defined(__APPLE__) || defined(__FreeBSD__)) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
+   /* The default stack size for new threads on OSX is small enough that
+    * we'll get hard crashes instead of 'maximum recursion depth exceeded'
+    * exceptions.
+    *
+    * The default stack size below is the minimal stack size where a
+    * simple recursive function doesn't cause a hard crash.
+    */
+#undef  THREAD_STACK_SIZE
+#define THREAD_STACK_SIZE       0x400000
+#endif
 /* for safety, ensure a viable minimum stacksize */
 #define THREAD_STACK_MIN        0x8000  /* 32kB */
 #else  /* !_POSIX_THREAD_ATTR_STACKSIZE */