[pypy-commit] pypy cffi-callback-onerror: hg merge default

arigo noreply at buildbot.pypy.org
Sat Jul 4 23:30:28 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-callback-onerror
Changeset: r78432:088ea8f70900
Date: 2015-07-04 23:19 +0200
http://bitbucket.org/pypy/pypy/changeset/088ea8f70900/

Log:	hg merge default

diff too long, truncating to 2000 out of 4366 lines

diff --git a/lib-python/2.7/test/test_urllib2.py b/lib-python/2.7/test/test_urllib2.py
--- a/lib-python/2.7/test/test_urllib2.py
+++ b/lib-python/2.7/test/test_urllib2.py
@@ -291,6 +291,7 @@
         self.req_headers = []
         self.data = None
         self.raise_on_endheaders = False
+        self.sock = None
         self._tunnel_headers = {}
 
     def __call__(self, host, timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
diff --git a/lib-python/2.7/urllib2.py b/lib-python/2.7/urllib2.py
--- a/lib-python/2.7/urllib2.py
+++ b/lib-python/2.7/urllib2.py
@@ -1200,6 +1200,12 @@
                 r = h.getresponse(buffering=True)
             except TypeError: # buffering kw not supported
                 r = h.getresponse()
+            # If the server does not send us a 'Connection: close' header,
+            # HTTPConnection assumes the socket should be left open. Manually
+            # mark the socket to be closed when this response object goes away.
+            if h.sock:
+                h.sock.close()
+                h.sock = None
 
         # Pick apart the HTTPResponse object to get the addinfourl
         # object initialized properly.
diff --git a/lib_pypy/_tkinter/tclobj.py b/lib_pypy/_tkinter/tclobj.py
--- a/lib_pypy/_tkinter/tclobj.py
+++ b/lib_pypy/_tkinter/tclobj.py
@@ -108,6 +108,8 @@
         return value.internalRep.doubleValue
     if value.typePtr == typeCache.IntType:
         return value.internalRep.longValue
+    if value.typePtr == typeCache.WideIntType:
+        return FromWideIntObj(app, value)
     if value.typePtr == typeCache.BigNumType and tklib.HAVE_LIBTOMMATH:
         return FromBignumObj(app, value)
     if value.typePtr == typeCache.ListType:
diff --git a/lib_pypy/_tkinter/tklib_build.py b/lib_pypy/_tkinter/tklib_build.py
--- a/lib_pypy/_tkinter/tklib_build.py
+++ b/lib_pypy/_tkinter/tklib_build.py
@@ -179,6 +179,7 @@
 typedef int... Tcl_WideInt;
 
 int Tcl_GetWideIntFromObj(Tcl_Interp *interp, Tcl_Obj *obj, Tcl_WideInt *value);
+Tcl_Obj *Tcl_NewWideIntObj(Tcl_WideInt value);
 """)
 
 if HAVE_LIBTOMMATH:
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.1.2
+Version: 1.2.0
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.1.2"
-__version_info__ = (1, 1, 2)
+__version__ = "1.2.0"
+__version_info__ = (1, 2, 0)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -328,6 +328,13 @@
         data.  Later, when this new cdata object is garbage-collected,
         'destructor(old_cdata_object)' will be called.
         """
+        try:
+            gcp = self._backend.gcp
+        except AttributeError:
+            pass
+        else:
+            return gcp(cdata, destructor)
+        #
         with self._lock:
             try:
                 gc_weakrefs = self.gc_weakrefs
@@ -429,6 +436,8 @@
             raise TypeError("ffi.include() expects an argument that is also of"
                             " type cffi.FFI, not %r" % (
                                 type(ffi_to_include).__name__,))
+        if ffi_to_include is self:
+            raise ValueError("self.include(self)")
         with ffi_to_include._lock:
             with self._lock:
                 self._parser.include(ffi_to_include._parser)
diff --git a/lib_pypy/cffi/cffi_opcode.py b/lib_pypy/cffi/cffi_opcode.py
--- a/lib_pypy/cffi/cffi_opcode.py
+++ b/lib_pypy/cffi/cffi_opcode.py
@@ -53,6 +53,7 @@
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
 OP_DLOPEN_CONST    = 37
+OP_GLOBAL_VAR_F    = 39
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -633,6 +633,8 @@
 
     def include(self, other):
         for name, tp in other._declarations.items():
+            if name.startswith('anonymous $enum_$'):
+                continue   # fix for test_anonymous_enum_include
             kind = name.split(' ', 1)[0]
             if kind in ('struct', 'union', 'enum', 'anonymous'):
                 self._declare(name, tp, included=True)
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -35,9 +35,6 @@
     def is_integer_type(self):
         return False
 
-    def sizeof_enabled(self):
-        return False
-
     def get_cached_btype(self, ffi, finishlist, can_delay=False):
         try:
             BType = ffi._cached_btypes[self]
@@ -80,8 +77,7 @@
 
 
 class BasePrimitiveType(BaseType):
-    def sizeof_enabled(self):
-        return True
+    pass
 
 
 class PrimitiveType(BasePrimitiveType):
@@ -205,9 +201,6 @@
 class FunctionPtrType(BaseFunctionType):
     _base_pattern = '(*&)(%s)'
 
-    def sizeof_enabled(self):
-        return True
-
     def build_backend_type(self, ffi, finishlist):
         result = self.result.get_cached_btype(ffi, finishlist)
         args = []
@@ -233,9 +226,6 @@
             extra = self._base_pattern
         self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra)
 
-    def sizeof_enabled(self):
-        return True
-
     def build_backend_type(self, ffi, finishlist):
         BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True)
         return global_cache(self, ffi, 'new_pointer_type', BItem)
@@ -276,9 +266,6 @@
         self.c_name_with_marker = (
             self.item.c_name_with_marker.replace('&', brackets))
 
-    def sizeof_enabled(self):
-        return self.item.sizeof_enabled() and self.length is not None
-
     def resolve_length(self, newlength):
         return ArrayType(self.item, newlength)
 
@@ -433,9 +420,6 @@
             from . import ffiplatform
             raise ffiplatform.VerificationMissing(self._get_c_name())
 
-    def sizeof_enabled(self):
-        return self.fldtypes is not None
-
     def build_backend_type(self, ffi, finishlist):
         self.check_not_partial()
         finishlist.append(self)
@@ -464,9 +448,6 @@
         self.baseinttype = baseinttype
         self.build_c_name_with_marker()
 
-    def sizeof_enabled(self):
-        return True     # not strictly true, but external enums are obscure
-
     def force_the_name(self, forcename):
         StructOrUnionOrEnum.force_the_name(self, forcename)
         if self.forcename is None:
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/cffi/parse_c_type.h
@@ -26,6 +26,7 @@
 #define _CFFI_OP_GLOBAL_VAR     33
 #define _CFFI_OP_DLOPEN_FUNC    35
 #define _CFFI_OP_DLOPEN_CONST   37
+#define _CFFI_OP_GLOBAL_VAR_F   39
 
 #define _CFFI_PRIM_VOID          0
 #define _CFFI_PRIM_BOOL          1
diff --git a/lib_pypy/cffi/recompiler.py b/lib_pypy/cffi/recompiler.py
--- a/lib_pypy/cffi/recompiler.py
+++ b/lib_pypy/cffi/recompiler.py
@@ -981,10 +981,6 @@
         if not self.target_is_python and tp.is_integer_type():
             type_op = CffiOp(OP_CONSTANT_INT, -1)
         else:
-            if not tp.sizeof_enabled():
-                raise ffiplatform.VerificationError(
-                    "constant '%s' is of type '%s', whose size is not known"
-                    % (name, tp._get_c_name()))
             if self.target_is_python:
                 const_kind = OP_DLOPEN_CONST
             else:
@@ -1069,18 +1065,36 @@
         self._do_collect_type(self._global_type(tp, name))
 
     def _generate_cpy_variable_decl(self, tp, name):
-        pass
+        prnt = self._prnt
+        tp = self._global_type(tp, name)
+        if isinstance(tp, model.ArrayType) and tp.length is None:
+            tp = tp.item
+            ampersand = ''
+        else:
+            ampersand = '&'
+        # This code assumes that casts from "tp *" to "void *" is a
+        # no-op, i.e. a function that returns a "tp *" can be called
+        # as if it returned a "void *".  This should be generally true
+        # on any modern machine.  The only exception to that rule (on
+        # uncommon architectures, and as far as I can tell) might be
+        # if 'tp' were a function type, but that is not possible here.
+        # (If 'tp' is a function _pointer_ type, then casts from "fn_t
+        # **" to "void *" are again no-ops, as far as I can tell.)
+        prnt('static ' + tp.get_c_name('*_cffi_var_%s(void)' % (name,)))
+        prnt('{')
+        prnt('  return %s(%s);' % (ampersand, name))
+        prnt('}')
+        prnt()
 
     def _generate_cpy_variable_ctx(self, tp, name):
         tp = self._global_type(tp, name)
         type_index = self._typesdict[tp]
-        type_op = CffiOp(OP_GLOBAL_VAR, type_index)
-        if tp.sizeof_enabled():
-            size = "sizeof(%s)" % (name,)
+        if self.target_is_python:
+            op = OP_GLOBAL_VAR
         else:
-            size = 0
+            op = OP_GLOBAL_VAR_F
         self._lsts["global"].append(
-            GlobalExpr(name, '&%s' % name, type_op, size))
+            GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index)))
 
     # ----------
     # emitting the opcodes for individual types
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -135,7 +135,7 @@
 Here are some more technical details.  This issue affects the precise
 time at which ``__del__`` methods are called, which
 is not reliable in PyPy (nor Jython nor IronPython).  It also means that
-weak references may stay alive for a bit longer than expected.  This
+**weak references** may stay alive for a bit longer than expected.  This
 makes "weak proxies" (as returned by ``weakref.proxy()``) somewhat less
 useful: they will appear to stay alive for a bit longer in PyPy, and
 suddenly they will really be dead, raising a ``ReferenceError`` on the
@@ -143,6 +143,24 @@
 ``ReferenceError`` at any place that uses them.  (Or, better yet, don't use
 ``weakref.proxy()`` at all; use ``weakref.ref()``.)
 
+Note a detail in the `documentation for weakref callbacks`__:
+
+    If callback is provided and not None, *and the returned weakref
+    object is still alive,* the callback will be called when the object
+    is about to be finalized.
+
+There are cases where, due to CPython's refcount semantics, a weakref
+dies immediately before or after the objects it points to (typically
+with some circular reference).  If it happens to die just after, then
+the callback will be invoked.  In a similar case in PyPy, both the
+object and the weakref will be considered as dead at the same time,
+and the callback will not be invoked.  (Issue `#2030`__)
+
+.. __: https://docs.python.org/2/library/weakref.html
+.. __: https://bitbucket.org/pypy/pypy/issue/2030/
+
+---------------------------------
+
 There are a few extra implications from the difference in the GC.  Most
 notably, if an object has a ``__del__``, the ``__del__`` is never called more
 than once in PyPy; but CPython will call the same ``__del__`` several times
@@ -321,9 +339,8 @@
 Miscellaneous
 -------------
 
-* Hash randomization (``-R``) is ignored in PyPy.  As documented in
-  http://bugs.python.org/issue14621, some of us believe it has no
-  purpose in CPython either.
+* Hash randomization (``-R``) `is ignored in PyPy`_.  In CPython
+  before 3.4 it has `little point`_.
 
 * You can't store non-string keys in type objects.  For example::
 
@@ -338,7 +355,8 @@
   for about 1400 calls.
 
 * since the implementation of dictionary is different, the exact number
-  which ``__hash__`` and ``__eq__`` are called is different. Since CPython
+  of times that ``__hash__`` and ``__eq__`` are called is different. 
+  Since CPython
   does not give any specific guarantees either, don't rely on it.
 
 * assignment to ``__class__`` is limited to the cases where it
@@ -395,3 +413,12 @@
   interactive mode. In a released version, this behaviour is suppressed, but
   setting the environment variable PYPY_IRC_TOPIC will bring it back. Note that
   downstream package providers have been known to totally disable this feature.
+
+* PyPy's readline module was rewritten from scratch: it is not GNU's
+  readline.  It should be mostly compatible, and it adds multiline
+  support (see ``multiline_input()``).  On the other hand,
+  ``parse_and_bind()`` calls are ignored (issue `#2072`_).
+
+.. _`is ignored in PyPy`: http://bugs.python.org/issue14621
+.. _`little point`: http://events.ccc.de/congress/2012/Fahrplan/events/5152.en.html
+.. _`#2072`: https://bitbucket.org/pypy/pypy/issue/2072/
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -6,15 +6,9 @@
 C. It was developed in collaboration with Roberto De Ioris from the `uwsgi`_
 project. The `PyPy uwsgi plugin`_ is a good example of using the embedding API.
 
-**NOTE**: As of 1st of December, PyPy comes with ``--shared`` by default
-on linux, linux64 and windows. We will make it the default on all platforms
-by the time of the next release.
-
-The first thing that you need is to compile PyPy yourself with the option
-``--shared``. We plan to make ``--shared`` the default in the future. Consult
-the `how to compile PyPy`_ doc for details. This will result in ``libpypy.so``
-or ``pypy.dll`` file or something similar, depending on your platform. Consult
-your platform specification for details.
+**NOTE**: You need a PyPy compiled with the option ``--shared``, i.e.
+with a ``libpypy-c.so`` or ``pypy-c.dll`` file.  This is the default in
+recent versions of PyPy.
 
 The resulting shared library exports very few functions, however they are
 enough to accomplish everything you need, provided you follow a few principles.
diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -70,6 +70,20 @@
 .. _`use virtualenv (as documented here)`: getting-started.html#installing-using-virtualenv
 
 
+Module xyz does not work in the sandboxed PyPy?
+-----------------------------------------------
+
+You cannot import *any* extension module in a `sandboxed PyPy`_,
+sorry.  Even the built-in modules available are very limited.
+Sandboxing in PyPy is a good proof of concept, really safe IMHO, but
+it is only a proof of concept.  It seriously requires someone working
+on it.  Before this occurs, it can only be used it for "pure Python"
+examples: programs that import mostly nothing (or only pure Python
+modules, recursively).
+
+.. _`sandboxed PyPy`: sandbox.html
+
+
 .. _`See below.`:
 
 Do CPython Extension modules work with PyPy?
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -11,3 +11,14 @@
 .. branch: stdlib-2.7.10
 
 Update stdlib to version 2.7.10
+
+.. branch: issue2062
+
+.. branch: disable-unroll-for-short-loops
+The JIT no longer performs loop unrolling if the loop compiles to too much code.
+
+.. branch: run-create_cffi_imports
+
+Build cffi import libraries as part of translation by monkey-patching an 
+aditional task into translation
+
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -1,6 +1,6 @@
 import py
 
-import os, sys
+import os, sys, subprocess
 
 import pypy
 from pypy.interpreter import gateway
@@ -298,6 +298,44 @@
         wrapstr = 'space.wrap(%r)' % (options)
         pypy.module.sys.Module.interpleveldefs['pypy_translation_info'] = wrapstr
 
+        # HACKHACKHACK
+        # ugly hack to modify target goal from compile_c to build_cffi_imports
+        # this should probably get cleaned up and merged with driver.create_exe
+        from rpython.translator.driver import taskdef
+        import types
+
+        class Options(object):
+            pass
+
+
+        def mkexename(name):
+            if sys.platform == 'win32':
+                name = name.new(ext='exe')
+            return name
+
+        @taskdef(['compile_c'], "Create cffi bindings for modules")
+        def task_build_cffi_imports(self):
+            from pypy.tool.build_cffi_imports import create_cffi_import_libraries
+            ''' Use cffi to compile cffi interfaces to modules'''
+            exename = mkexename(driver.compute_exe_name())
+            basedir = exename
+            while not basedir.join('include').exists():
+                _basedir = basedir.dirpath()
+                if _basedir == basedir:
+                    raise ValueError('interpreter %s not inside pypy repo', 
+                                     str(exename))
+                basedir = _basedir
+            modules = self.config.objspace.usemodules.getpaths()
+            options = Options()
+            # XXX possibly adapt options using modules
+            failures = create_cffi_import_libraries(exename, options, basedir)
+            # if failures, they were already printed
+            print  >> sys.stderr, str(exename),'successfully built, but errors while building the above modules will be ignored'
+        driver.task_build_cffi_imports = types.MethodType(task_build_cffi_imports, driver)
+        driver.tasks['build_cffi_imports'] = driver.task_build_cffi_imports, ['compile_c']
+        driver.default_goal = 'build_cffi_imports'
+        # HACKHACKHACK end
+
         return self.get_entry_point(config)
 
     def jitpolicy(self, driver):
diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py
--- a/pypy/interpreter/app_main.py
+++ b/pypy/interpreter/app_main.py
@@ -40,6 +40,11 @@
 PYPYLOG: If set to a non-empty value, enable logging.
 """
 
+try:
+    from __pypy__ import get_hidden_tb, hidden_applevel
+except ImportError:
+    get_hidden_tb = lambda: sys.exc_info()[2]
+    hidden_applevel = lambda f: f
 import sys
 
 DEBUG = False       # dump exceptions before calling the except hook
@@ -63,6 +68,7 @@
             exitcode = 1
     raise SystemExit(exitcode)
 
+ at hidden_applevel
 def run_toplevel(f, *fargs, **fkwds):
     """Calls f() and handles all OperationErrors.
     Intended use is to run the main program or one interactive statement.
@@ -87,13 +93,13 @@
 
     except SystemExit as e:
         handle_sys_exit(e)
-    except:
-        display_exception()
+    except BaseException as e:
+        display_exception(e)
         return False
     return True   # success
 
-def display_exception():
-    etype, evalue, etraceback = sys.exc_info()
+def display_exception(e):
+    etype, evalue, etraceback = type(e), e, get_hidden_tb()
     try:
         # extra debugging info in case the code below goes very wrong
         if DEBUG and hasattr(sys, 'stderr'):
@@ -119,11 +125,11 @@
         hook(etype, evalue, etraceback)
         return # done
 
-    except:
+    except BaseException as e:
         try:
             stderr = sys.stderr
             print >> stderr, 'Error calling sys.excepthook:'
-            originalexcepthook(*sys.exc_info())
+            originalexcepthook(type(e), e, e.__traceback__)
             print >> stderr
             print >> stderr, 'Original exception was:'
         except:
@@ -509,6 +515,7 @@
 
     return options
 
+ at hidden_applevel
 def run_command_line(interactive,
                      inspect,
                      run_command,
@@ -597,6 +604,7 @@
             # Put '' on sys.path
             sys.path.insert(0, '')
 
+            @hidden_applevel
             def run_it():
                 exec run_command in mainmodule.__dict__
             success = run_toplevel(run_it)
@@ -634,6 +642,7 @@
                         print >> sys.stderr, "Could not open PYTHONSTARTUP"
                         print >> sys.stderr, "IOError:", e
                     else:
+                        @hidden_applevel
                         def run_it():
                             co_python_startup = compile(startup,
                                                         python_startup,
@@ -650,6 +659,7 @@
                 inspect = True
             else:
                 # If not interactive, just read and execute stdin normally.
+                @hidden_applevel
                 def run_it():
                     co_stdin = compile(sys.stdin.read(), '<stdin>', 'exec',
                                        PyCF_ACCEPT_NULL_BYTES)
@@ -689,7 +699,7 @@
     except SystemExit as e:
         status = e.code
         if inspect_requested():
-            display_exception()
+            display_exception(e)
     else:
         status = not success
 
@@ -743,6 +753,7 @@
     # This is important for py3k
     sys.executable = executable
 
+ at hidden_applevel
 def entry_point(executable, argv):
     # note that before calling setup_bootstrap_path, we are limited because we
     # cannot import stdlib modules. In particular, we cannot use unicode
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -1,6 +1,7 @@
 import sys
 from pypy.interpreter.error import OperationError, get_cleared_operation_error
 from rpython.rlib.unroll import unrolling_iterable
+from rpython.rlib.objectmodel import specialize
 from rpython.rlib import jit
 
 TICK_COUNTER_STEP = 100
@@ -214,13 +215,21 @@
             self._trace(frame, 'exception', None, operationerr)
         #operationerr.print_detailed_traceback(self.space)
 
-    def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
+    @specialize.arg(1)
+    def sys_exc_info(self, for_hidden=False):
         """Implements sys.exc_info().
-        Return an OperationError instance or None."""
+        Return an OperationError instance or None.
+
+        Ignores exceptions within hidden frames unless for_hidden=True
+        is specified.
+
+        # NOTE: the result is not the wrapped sys.exc_info() !!!
+
+        """
         frame = self.gettopframe()
         while frame:
             if frame.last_exception is not None:
-                if (not frame.hide() or
+                if ((for_hidden or not frame.hide()) or
                         frame.last_exception is
                             get_cleared_operation_error(self.space)):
                     return frame.last_exception
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -15,7 +15,10 @@
         self.running = False
 
     def descr__repr__(self, space):
-        code_name = self.pycode.co_name
+        if self.pycode is None:
+            code_name = '<finished>'
+        else:
+            code_name = self.pycode.co_name
         addrstring = self.getaddrstring(space)
         return space.wrap("<generator object %s at 0x%s>" %
                           (code_name, addrstring))
@@ -45,6 +48,8 @@
         w_framestate, w_running = args_w
         if space.is_w(w_framestate, space.w_None):
             self.frame = None
+            self.space = space
+            self.pycode = None
         else:
             frame = instantiate(space.FrameClass)   # XXX fish
             frame.descr__setstate__(space, w_framestate)
@@ -62,9 +67,10 @@
 
     def send_ex(self, w_arg, operr=None):
         pycode = self.pycode
-        if jit.we_are_jitted() and should_not_inline(pycode):
-            generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
-                                                  operr=operr, pycode=pycode)
+        if pycode is not None:
+            if jit.we_are_jitted() and should_not_inline(pycode):
+                generatorentry_driver.jit_merge_point(gen=self, w_arg=w_arg,
+                                                    operr=operr, pycode=pycode)
         return self._send_ex(w_arg, operr)
 
     def _send_ex(self, w_arg, operr):
@@ -158,7 +164,10 @@
         return self.pycode
 
     def descr__name__(self, space):
-        code_name = self.pycode.co_name
+        if self.pycode is None:
+            code_name = '<finished>'
+        else:
+            code_name = self.pycode.co_name
         return space.wrap(code_name)
 
     # Results can be either an RPython list of W_Root, or it can be an
diff --git a/pypy/interpreter/pytraceback.py b/pypy/interpreter/pytraceback.py
--- a/pypy/interpreter/pytraceback.py
+++ b/pypy/interpreter/pytraceback.py
@@ -60,7 +60,6 @@
 
 
 def check_traceback(space, w_tb, msg):
-    from pypy.interpreter.typedef import PyTraceback
     if w_tb is None or not space.isinstance_w(w_tb, space.gettypeobject(PyTraceback.typedef)):
         raise OperationError(space.w_TypeError, space.wrap(msg))
     return w_tb
diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py
--- a/pypy/interpreter/test/test_zzpickle_and_slow.py
+++ b/pypy/interpreter/test/test_zzpickle_and_slow.py
@@ -491,6 +491,22 @@
         assert pack.mod is result
 
 
+    def test_pickle_generator_crash(self):
+        import pickle
+
+        def f():
+            yield 0
+
+        x = f()
+        x.next()
+        try:
+            x.next()
+        except StopIteration:
+            y = pickle.loads(pickle.dumps(x))
+        assert 'finished' in y.__name__
+        assert 'finished' in repr(y)
+        assert y.gi_code is None
+
 class AppTestGeneratorCloning:
 
     def setup_class(cls):
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -71,6 +71,8 @@
         'debug_print_once'          : 'interp_debug.debug_print_once',
         'debug_flush'               : 'interp_debug.debug_flush',
         'builtinify'                : 'interp_magic.builtinify',
+        'hidden_applevel'           : 'interp_magic.hidden_applevel',
+        'get_hidden_tb'             : 'interp_magic.get_hidden_tb',
         'lookup_special'            : 'interp_magic.lookup_special',
         'do_what_I_mean'            : 'interp_magic.do_what_I_mean',
         'validate_fd'               : 'interp_magic.validate_fd',
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -59,6 +59,20 @@
     bltn = BuiltinFunction(func)
     return space.wrap(bltn)
 
+def hidden_applevel(space, w_func):
+    """Decorator that hides a function's frame from app-level"""
+    from pypy.interpreter.function import Function
+    func = space.interp_w(Function, w_func)
+    func.getcode().hidden_applevel = True
+    return w_func
+
+def get_hidden_tb(space):
+    """Return the traceback of the current exception being handled by a
+    frame hidden from applevel.
+    """
+    operr = space.getexecutioncontext().sys_exc_info(for_hidden=True)
+    return space.w_None if operr is None else space.wrap(operr.get_traceback())
+
 @unwrap_spec(meth=str)
 def lookup_special(space, w_obj, meth):
     """Lookup up a special method on an object."""
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -27,6 +27,52 @@
         assert A.a is not A.__dict__['a']
         assert A.b is A.__dict__['b']
 
+    def test_hidden_applevel(self):
+        import __pypy__
+        import sys
+
+        @__pypy__.hidden_applevel
+        def sneak(): (lambda: 1/0)()
+        try:
+            sneak()
+        except ZeroDivisionError as e:
+            tb = sys.exc_info()[2]
+            assert tb.tb_frame == sys._getframe()
+            assert tb.tb_next.tb_frame.f_code.co_name == '<lambda>'
+        else:
+            assert False, 'Expected ZeroDivisionError'
+
+    def test_hidden_applevel_frames(self):
+        import __pypy__
+        import sys
+
+        @__pypy__.hidden_applevel
+        def test_hidden():
+            assert sys._getframe().f_code.co_name != 'test_hidden'
+            def e(): 1/0
+            try: e()
+            except ZeroDivisionError as e:
+                assert sys.exc_info() == (None, None, None)
+            else: assert False
+            return 2
+        assert test_hidden() == 2
+
+    def test_get_hidden_tb(self):
+        import __pypy__
+        import sys
+
+        @__pypy__.hidden_applevel
+        def test_hidden_with_tb():
+            def not_hidden(): 1/0
+            try: not_hidden()
+            except ZeroDivisionError as e:
+                assert sys.exc_info() == (None, None, None)
+                tb = __pypy__.get_hidden_tb()
+                assert tb.tb_frame.f_code.co_name == 'not_hidden'
+                return True
+            else: return False
+        assert test_hidden_with_tb()
+
     def test_lookup_special(self):
         from __pypy__ import lookup_special
         class X(object):
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -2,7 +2,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib import rdynload
 
-VERSION = "1.1.2"
+VERSION = "1.2.0"
 
 
 class Module(MixedModule):
@@ -37,6 +37,7 @@
         'from_handle': 'handle.from_handle',
         '_get_types': 'func._get_types',
         'from_buffer': 'func.from_buffer',
+        'gcp': 'func.gcp',
 
         'string': 'func.string',
         'buffer': 'cbuffer.buffer',
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -36,7 +36,10 @@
                         self.libname)
         try:
             cdata = dlsym(self.libhandle, name)
+            found = bool(cdata)
         except KeyError:
+            found = False
+        if not found:
             raise oefmt(self.ffi.w_FFIError,
                         "symbol '%s' not found in library '%s'",
                         name, self.libname)
diff --git a/pypy/module/_cffi_backend/cffi_opcode.py b/pypy/module/_cffi_backend/cffi_opcode.py
--- a/pypy/module/_cffi_backend/cffi_opcode.py
+++ b/pypy/module/_cffi_backend/cffi_opcode.py
@@ -53,6 +53,7 @@
 OP_GLOBAL_VAR      = 33
 OP_DLOPEN_FUNC     = 35
 OP_DLOPEN_CONST    = 37
+OP_GLOBAL_VAR_F    = 39
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/pypy/module/_cffi_backend/cglob.py b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -2,23 +2,38 @@
 from pypy.interpreter.typedef import TypeDef
 from pypy.module._cffi_backend.cdataobj import W_CData
 from pypy.module._cffi_backend import newtype
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+FNPTR = rffi.CCallback([], rffi.VOIDP)
 
 
 class W_GlobSupport(W_Root):
-    def __init__(self, space, w_ctype, ptr):
+    _immutable_fields_ = ['w_ctype', 'ptr', 'fetch_addr']
+
+    def __init__(self, space, w_ctype, ptr=lltype.nullptr(rffi.CCHARP.TO),
+                 fetch_addr=lltype.nullptr(rffi.VOIDP.TO)):
         self.space = space
         self.w_ctype = w_ctype
         self.ptr = ptr
+        self.fetch_addr = rffi.cast(FNPTR, fetch_addr)
+
+    def fetch_global_var_addr(self):
+        if self.ptr:
+            return self.ptr
+        result = self.fetch_addr()
+        return rffi.cast(rffi.CCHARP, result)
 
     def read_global_var(self):
-        return self.w_ctype.convert_to_object(self.ptr)
+        return self.w_ctype.convert_to_object(self.fetch_global_var_addr())
 
     def write_global_var(self, w_newvalue):
-        self.w_ctype.convert_from_object(self.ptr, w_newvalue)
+        self.w_ctype.convert_from_object(self.fetch_global_var_addr(),
+                                         w_newvalue)
 
     def address(self):
         w_ctypeptr = newtype.new_pointer_type(self.space, self.w_ctype)
-        return W_CData(self.space, self.ptr, w_ctypeptr)
+        return W_CData(self.space, self.fetch_global_var_addr(), w_ctypeptr)
 
 W_GlobSupport.typedef = TypeDef("FFIGlobSupport")
 W_GlobSupport.typedef.acceptable_as_base_class = False
diff --git a/pypy/module/_cffi_backend/ctypefunc.py b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -143,7 +143,7 @@
     @jit.unroll_safe
     def _call(self, funcaddr, args_w):
         space = self.space
-        cif_descr = self.cif_descr
+        cif_descr = self.cif_descr   # 'self' should have been promoted here
         size = cif_descr.exchange_size
         mustfree_max_plus_1 = 0
         buffer = lltype.malloc(rffi.CCHARP.TO, size, flavor='raw')
diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py
--- a/pypy/module/_cffi_backend/ctypeprim.py
+++ b/pypy/module/_cffi_backend/ctypeprim.py
@@ -134,8 +134,7 @@
 
     def convert_to_object(self, cdata):
         unichardata = rffi.cast(rffi.CWCHARP, cdata)
-        s = rffi.wcharpsize2unicode(unichardata, 1)
-        return self.space.wrap(s)
+        return self.space.wrap(unichardata[0])
 
     def string(self, cdataobj, maxlen):
         with cdataobj as ptr:
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -223,9 +223,13 @@
         if (isinstance(w_cdata, cdataobj.W_CDataNewOwning) or
             isinstance(w_cdata, cdataobj.W_CDataPtrToStructOrUnion)):
             if i != 0:
-                space = self.space
-                raise oefmt(space.w_IndexError,
+                raise oefmt(self.space.w_IndexError,
                             "cdata '%s' can only be indexed by 0", self.name)
+        else:
+            if not w_cdata.unsafe_escaping_ptr():
+                raise oefmt(self.space.w_RuntimeError,
+                            "cannot dereference null pointer from cdata '%s'",
+                            self.name)
         return self
 
     def _check_slice_index(self, w_cdata, start, stop):
diff --git a/pypy/module/_cffi_backend/ffi_obj.py b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -542,13 +542,18 @@
 
 
 @jit.dont_look_inside
-def W_FFIObject___new__(space, w_subtype, __args__):
-    r = space.allocate_instance(W_FFIObject, w_subtype)
+def make_plain_ffi_object(space, w_ffitype=None):
+    if w_ffitype is None:
+        w_ffitype = space.gettypefor(W_FFIObject)
+    r = space.allocate_instance(W_FFIObject, w_ffitype)
     # get in 'src_ctx' a NULL which translation doesn't consider to be constant
     src_ctx = rffi.cast(parse_c_type.PCTX, 0)
     r.__init__(space, src_ctx)
     return space.wrap(r)
 
+def W_FFIObject___new__(space, w_subtype, __args__):
+    return make_plain_ffi_object(space, w_subtype)
+
 def make_CData(space):
     return space.gettypefor(W_CData)
 
diff --git a/pypy/module/_cffi_backend/func.py b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -105,3 +105,18 @@
                     "raw address on PyPy", w_x)
     #
     return cdataobj.W_CDataFromBuffer(space, _cdata, w_ctype, buf, w_x)
+
+# ____________________________________________________________
+
+class ConstantFFI:
+    ffi1 = None
+    def _cleanup_(self):
+        self.ffi1 = None
+constant_ffi = ConstantFFI()
+
+ at unwrap_spec(w_cdata=cdataobj.W_CData)
+def gcp(space, w_cdata, w_destructor):
+    if constant_ffi.ffi1 is None:
+        from pypy.module._cffi_backend import ffi_obj
+        constant_ffi.ffi1 = ffi_obj.make_plain_ffi_object(space)
+    return constant_ffi.ffi1.descr_gc(w_cdata, w_destructor)
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -60,12 +60,12 @@
             self.ffi, self.ctx.c_types, getarg(g.c_type_op))
         assert isinstance(rawfunctype, realize_c_type.W_RawFuncType)
         #
-        w_ct, locs = rawfunctype.unwrap_as_nostruct_fnptr(self.ffi)
+        rawfunctype.prepare_nostruct_fnptr(self.ffi)
         #
         ptr = rffi.cast(rffi.CCHARP, g.c_address)
         assert ptr
-        return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn, w_ct,
-                                 locs, rawfunctype, fnname, self.libname)
+        return W_FunctionWrapper(self.space, ptr, g.c_size_or_direct_fn,
+                                 rawfunctype, fnname, self.libname)
 
     @jit.elidable_promote()
     def _get_attr_elidable(self, attr):
@@ -102,6 +102,8 @@
                 #
             elif op == cffi_opcode.OP_GLOBAL_VAR:
                 # A global variable of the exact type specified here
+                # (nowadays, only used by the ABI mode or backend
+                # compatibility; see OP_GLOBAL_F for the API mode
                 w_ct = realize_c_type.realize_c_type(
                     self.ffi, self.ctx.c_types, getarg(g.c_type_op))
                 g_size = rffi.cast(lltype.Signed, g.c_size_or_direct_fn)
@@ -113,7 +115,13 @@
                 ptr = rffi.cast(rffi.CCHARP, g.c_address)
                 if not ptr:   # for dlopen() style
                     ptr = self.cdlopen_fetch(attr)
-                w_result = cglob.W_GlobSupport(space, w_ct, ptr)
+                w_result = cglob.W_GlobSupport(space, w_ct, ptr=ptr)
+                #
+            elif op == cffi_opcode.OP_GLOBAL_VAR_F:
+                w_ct = realize_c_type.realize_c_type(
+                    self.ffi, self.ctx.c_types, getarg(g.c_type_op))
+                w_result = cglob.W_GlobSupport(space, w_ct,
+                                               fetch_addr=g.c_address)
                 #
             elif (op == cffi_opcode.OP_CONSTANT_INT or
                   op == cffi_opcode.OP_ENUM):
@@ -131,6 +139,9 @@
                     realize_c_type.FUNCPTR_FETCH_CHARP,
                     g.c_address)
                 if w_ct.size <= 0:
+                    raise oefmt(self.ffi.w_FFIError,
+                                "constant '%s' is of type '%s', "
+                                "whose size is not known", attr, w_ct.name)
                     raise oefmt(space.w_SystemError,
                                 "constant has no known size")
                 if not fetch_funcptr:   # for dlopen() style
@@ -172,7 +183,11 @@
             w_value = self._build_attr(attr)
             if w_value is None:
                 if is_getattr and attr == '__all__':
-                    return self.dir1(ignore_type=cffi_opcode.OP_GLOBAL_VAR)
+                    return self.dir1(ignore_global_vars=True)
+                if is_getattr and attr == '__dict__':
+                    return self.full_dict_copy()
+                if is_getattr and attr == '__name__':
+                    return self.descr_repr()
                 raise oefmt(self.space.w_AttributeError,
                             "cffi library '%s' has no function, constant "
                             "or global variable named '%s'",
@@ -202,16 +217,31 @@
     def descr_dir(self):
         return self.dir1()
 
-    def dir1(self, ignore_type=-1):
+    def dir1(self, ignore_global_vars=False):
         space = self.space
         total = rffi.getintfield(self.ctx, 'c_num_globals')
         g = self.ctx.c_globals
         names_w = []
         for i in range(total):
-            if getop(g[i].c_type_op) != ignore_type:
-                names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
+            if ignore_global_vars:
+                op = getop(g[i].c_type_op)
+                if (op == cffi_opcode.OP_GLOBAL_VAR or
+                    op == cffi_opcode.OP_GLOBAL_VAR_F):
+                    continue
+            names_w.append(space.wrap(rffi.charp2str(g[i].c_name)))
         return space.newlist(names_w)
 
+    def full_dict_copy(self):
+        space = self.space
+        total = rffi.getintfield(self.ctx, 'c_num_globals')
+        g = self.ctx.c_globals
+        w_result = space.newdict()
+        for i in range(total):
+            w_attr = space.wrap(rffi.charp2str(g[i].c_name))
+            w_value = self._get_attr(w_attr)
+            space.setitem(w_result, w_attr, w_value)
+        return w_result
+
     def address_of_func_or_global_var(self, varname):
         # rebuild a string object from 'varname', to do typechecks and
         # to force a unicode back to a plain string
@@ -224,7 +254,8 @@
         if isinstance(w_value, W_FunctionWrapper):
             # '&func' returns a regular cdata pointer-to-function
             if w_value.directfnptr:
-                return W_CData(space, w_value.directfnptr, w_value.ctype)
+                ctype = w_value.typeof(self.ffi)
+                return W_CData(space, w_value.directfnptr, ctype)
             else:
                 return w_value    # backward compatibility
         #
diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py
--- a/pypy/module/_cffi_backend/realize_c_type.py
+++ b/pypy/module/_cffi_backend/realize_c_type.py
@@ -1,4 +1,5 @@
 import sys
+from rpython.rlib import jit
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.objectmodel import specialize
 from rpython.rtyper.lltypesystem import lltype, rffi
@@ -135,8 +136,12 @@
 
 class W_RawFuncType(W_Root):
     """Temporary: represents a C function type (not a function pointer)"""
+
+    _immutable_fields_ = ['nostruct_ctype', 'nostruct_locs', 'nostruct_nargs']
     _ctfuncptr = None
-    _nostruct_ctfuncptr = (None, None)
+    nostruct_ctype = None
+    nostruct_locs = None
+    nostruct_nargs = 0
 
     def __init__(self, opcodes, base_index):
         self.opcodes = opcodes
@@ -168,14 +173,16 @@
         assert self._ctfuncptr is not None
         return self._ctfuncptr
 
-    def unwrap_as_nostruct_fnptr(self, ffi):
-        # tweaked version: instead of returning the ctfuncptr corresponding
-        # exactly to the OP_FUNCTION ... OP_FUNCTION_END opcodes, return
-        # another one in which the struct args are replaced with ptr-to-
-        # struct, and a struct return value is replaced with a hidden first
-        # arg of type ptr-to-struct.  This is how recompiler.py produces
+    @jit.dont_look_inside
+    def prepare_nostruct_fnptr(self, ffi):
+        # tweaked version: instead of returning the ctfuncptr
+        # corresponding exactly to the OP_FUNCTION ... OP_FUNCTION_END
+        # opcodes, this builds in self.nostruct_ctype another one in
+        # which the struct args are replaced with ptr-to- struct, and
+        # a struct return value is replaced with a hidden first arg of
+        # type ptr-to-struct.  This is how recompiler.py produces
         # trampoline functions for PyPy.
-        if self._nostruct_ctfuncptr[0] is None:
+        if self.nostruct_ctype is None:
             fargs, fret, ellipsis = self._unpack(ffi)
             # 'locs' will be a string of the same length as the final fargs,
             # containing 'A' where a struct argument was detected, and 'R'
@@ -198,8 +205,10 @@
                 locs = None
             else:
                 locs = ''.join(locs)
-            self._nostruct_ctfuncptr = (ctfuncptr, locs)
-        return self._nostruct_ctfuncptr
+            self.nostruct_ctype = ctfuncptr
+            self.nostruct_locs = locs
+            self.nostruct_nargs = len(ctfuncptr.fargs) - (locs is not None and
+                                                          locs[0] == 'R')
 
     def unexpected_fn_type(self, ffi):
         fargs, fret, ellipsis = self._unpack(ffi)
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c
--- a/pypy/module/_cffi_backend/src/parse_c_type.c
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -362,7 +362,7 @@
 
             case TOK_INTEGER:
                 errno = 0;
-#ifndef MS_WIN32
+#ifndef _MSC_VER
                 if (sizeof(length) > sizeof(unsigned long))
                     length = strtoull(tok->p, &endptr, 0);
                 else
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -2099,8 +2099,7 @@
     p = cast(BVoidP, 123456)
     py.test.raises(TypeError, "p[0]")
     p = cast(BVoidP, 0)
-    if 'PY_DOT_PY' in globals(): py.test.skip("NULL crashes early on py.py")
-    py.test.raises(TypeError, "p[0]")
+    py.test.raises((TypeError, RuntimeError), "p[0]")
 
 def test_iter():
     BInt = new_primitive_type("int")
@@ -3333,6 +3332,15 @@
     check(4 | 8,  "CHB", "GTB")
     check(4 | 16, "CHB", "ROB")
 
+def test_dereference_null_ptr():
+    BInt = new_primitive_type("int")
+    BIntPtr = new_pointer_type(BInt)
+    p = cast(BIntPtr, 0)
+    py.test.raises(RuntimeError, "p[0]")
+    py.test.raises(RuntimeError, "p[0] = 42")
+    py.test.raises(RuntimeError, "p[42]")
+    py.test.raises(RuntimeError, "p[42] = -1")
+
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "1.1.2"
+    assert __version__ == "1.2.0"
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -4,6 +4,8 @@
     spaceconfig = dict(usemodules=('_cffi_backend', 'array'))
 
     def teardown_method(self, meth):
+        from pypy.module._cffi_backend.func import constant_ffi
+        constant_ffi._cleanup_()
         _clean_cache(self.space)
 
     def test_ffi_new(self):
@@ -234,9 +236,10 @@
             assert p1[0] == 123
             seen.append(1)
         ffi.gc(p, destructor=destructor)    # instantly forgotten
+        _cffi1_backend.gcp(p, destructor=destructor)
         for i in range(5):
             if seen:
                 break
             import gc
             gc.collect()
-        assert seen == [1]
+        assert seen == [1, 1]
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -16,8 +16,8 @@
         from cffi import ffiplatform
     except ImportError:
         py.test.skip("system cffi module not found or older than 1.0.0")
-    if cffi.__version_info__ < (1, 0, 4):
-        py.test.skip("system cffi module needs to be at least 1.0.4")
+    if cffi.__version_info__ < (1, 2, 0):
+        py.test.skip("system cffi module needs to be at least 1.2.0")
     space.appexec([], """():
         import _cffi_backend     # force it to be initialized
     """)
@@ -276,6 +276,15 @@
         """)
         lib.aa = 5
         assert dir(lib) == ['aa', 'ff', 'my_constant']
+        #
+        aaobj = lib.__dict__['aa']
+        assert not isinstance(aaobj, int)    # some internal object instead
+        assert lib.__dict__ == {
+            'ff': lib.ff,
+            'aa': aaobj,
+            'my_constant': -45}
+        lib.__dict__['ff'] = "??"
+        assert lib.ff(10) == 15
 
     def test_verify_opaque_struct(self):
         ffi, lib = self.prepare(
@@ -491,28 +500,33 @@
             "int foo(int x) { return x + 32; }")
         assert lib.foo(10) == 42
 
-    def test_bad_size_of_global_1(self):
-        ffi, lib = self.prepare(
-            "short glob;",
-            "test_bad_size_of_global_1",
-            "long glob;")
-        raises(ffi.error, getattr, lib, "glob")
-
-    def test_bad_size_of_global_2(self):
-        ffi, lib = self.prepare(
-            "int glob[10];",
-            "test_bad_size_of_global_2",
-            "int glob[9];")
-        e = raises(ffi.error, getattr, lib, "glob")
-        assert str(e.value) == ("global variable 'glob' should be 40 bytes "
-                                "according to the cdef, but is actually 36")
-
-    def test_unspecified_size_of_global(self):
+    def test_unspecified_size_of_global_1(self):
         ffi, lib = self.prepare(
             "int glob[];",
-            "test_unspecified_size_of_global",
+            "test_unspecified_size_of_global_1",
             "int glob[10];")
-        lib.glob    # does not crash
+        assert ffi.typeof(lib.glob) == ffi.typeof("int *")
+
+    def test_unspecified_size_of_global_2(self):
+        ffi, lib = self.prepare(
+            "int glob[][5];",
+            "test_unspecified_size_of_global_2",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+    def test_unspecified_size_of_global_3(self):
+        ffi, lib = self.prepare(
+            "int glob[][...];",
+            "test_unspecified_size_of_global_3",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]")
+
+    def test_unspecified_size_of_global_4(self):
+        ffi, lib = self.prepare(
+            "int glob[...][...];",
+            "test_unspecified_size_of_global_4",
+            "int glob[10][5];")
+        assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]")
 
     def test_include_1(self):
         ffi1, lib1 = self.prepare(
@@ -819,6 +833,22 @@
         assert isinstance(addr, ffi.CData)
         assert ffi.typeof(addr) == ffi.typeof("long(*)(long)")
 
+    def test_address_of_function_with_struct(self):
+        ffi, lib = self.prepare(
+            "struct foo_s { int x; }; long myfunc(struct foo_s);",
+            "test_addressof_function_with_struct", """
+                struct foo_s { int x; };
+                char myfunc(struct foo_s input) { return (char)(input.x + 42); }
+            """)
+        s = ffi.new("struct foo_s *", [5])[0]
+        assert lib.myfunc(s) == 47
+        assert not isinstance(lib.myfunc, ffi.CData)
+        assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)")
+        addr = ffi.addressof(lib, 'myfunc')
+        assert addr(s) == 47
+        assert isinstance(addr, ffi.CData)
+        assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)")
+
     def test_issue198(self):
         ffi, lib = self.prepare("""
             typedef struct{...;} opaque_t;
@@ -844,11 +874,22 @@
             """)
         assert lib.almost_forty_two == 42.25
 
+    def test_constant_of_unknown_size(self):
+        ffi, lib = self.prepare(
+            "typedef ... opaque_t;"
+            "const opaque_t CONSTANT;",
+            'test_constant_of_unknown_size',
+            "typedef int opaque_t;"
+            "const int CONSTANT = 42;")
+        e = raises(ffi.error, getattr, lib, 'CONSTANT')
+        assert str(e.value) == ("constant 'CONSTANT' is of "
+                                "type 'opaque_t', whose size is not known")
+
     def test_variable_of_unknown_size(self):
         ffi, lib = self.prepare("""
             typedef ... opaque_t;
             opaque_t globvar;
-        """, 'test_constant_of_unknown_size', """
+        """, 'test_variable_of_unknown_size', """
             typedef char opaque_t[6];
             opaque_t globvar = "hello";
         """)
@@ -984,5 +1025,35 @@
         assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib
         from _CFFI_test_import_from_lib.lib import MYFOO
         assert MYFOO == 42
-        assert not hasattr(lib, '__dict__')
+        assert hasattr(lib, '__dict__')
         assert lib.__all__ == ['MYFOO', 'mybar']   # but not 'myvar'
+        assert lib.__name__ == repr(lib)
+
+    def test_macro_var_callback(self):
+        ffi, lib = self.prepare(
+            "int my_value; int *(*get_my_value)(void);",
+            'test_macro_var_callback',
+            "int *(*get_my_value)(void);\n"
+            "#define my_value (*get_my_value())")
+        #
+        values = ffi.new("int[50]")
+        def it():
+            for i in range(50):
+                yield i
+        it = it()
+        #
+        @ffi.callback("int *(*)(void)")
+        def get_my_value():
+            return values + it.next()
+        lib.get_my_value = get_my_value
+        #
+        values[0] = 41
+        assert lib.my_value == 41            # [0]
+        p = ffi.addressof(lib, 'my_value')   # [1]
+        assert p == values + 1
+        assert p[-1] == 41
+        assert p[+1] == 0
+        lib.my_value = 42                    # [2]
+        assert values[2] == 42
+        assert p[-1] == 41
+        assert p[+1] == 42
diff --git a/pypy/module/_cffi_backend/wrapper.py b/pypy/module/_cffi_backend/wrapper.py
--- a/pypy/module/_cffi_backend/wrapper.py
+++ b/pypy/module/_cffi_backend/wrapper.py
@@ -19,12 +19,20 @@
     wrapper is callable, and the arguments it expects and returns
     are directly the struct/union.  Calling ffi.typeof(wrapper)
     also returns the original struct/union signature.
+
+    This class cannot be used for variadic functions.
     """
     _immutable_ = True
     common_doc_str = 'direct call to the C function of the same name'
 
-    def __init__(self, space, fnptr, directfnptr, ctype,
-                 locs, rawfunctype, fnname, modulename):
+    def __init__(self, space, fnptr, directfnptr,
+                 rawfunctype, fnname, modulename):
+        # everything related to the type of the function is accessed
+        # as immutable attributes of the 'rawfunctype' object, which
+        # is a W_RawFuncType.  This gives us an obvious thing to
+        # promote in order to do the call.
+        ctype = rawfunctype.nostruct_ctype
+        locs = rawfunctype.nostruct_locs
         assert isinstance(ctype, W_CTypeFunc)
         assert ctype.cif_descr is not None     # not for '...' functions
         assert locs is None or len(ctype.fargs) == len(locs)
@@ -32,83 +40,86 @@
         self.space = space
         self.fnptr = fnptr
         self.directfnptr = directfnptr
-        self.ctype = ctype
-        self.locs = locs
         self.rawfunctype = rawfunctype
         self.fnname = fnname
         self.modulename = modulename
-        self.nargs_expected = len(ctype.fargs) - (locs is not None and
-                                                  locs[0] == 'R')
 
     def typeof(self, ffi):
         return self.rawfunctype.unwrap_as_fnptr(ffi)
 
-    @jit.unroll_safe
-    def _prepare(self, args_w, start_index):
-        # replaces struct/union arguments with ptr-to-struct/union arguments
+    def descr_call(self, args_w):
         space = self.space
-        locs = self.locs
-        fargs = self.ctype.fargs
-        for i in range(start_index, len(locs)):
-            if locs[i] != 'A':
-                continue
-            w_arg = args_w[i]
-            farg = fargs[i]      # <ptr to struct/union>
-            assert isinstance(farg, W_CTypePtrOrArray)
-            if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem:
-                # fast way: we are given a W_CData "struct", so just make
-                # a new W_CData "ptr-to-struct" which points to the same
-                # raw memory.  We use unsafe_escaping_ptr(), so we have to
-                # make sure the original 'w_arg' stays alive; the easiest
-                # is to build an instance of W_CDataPtrToStructOrUnion.
-                w_arg = W_CDataPtrToStructOrUnion(
-                    space, w_arg.unsafe_escaping_ptr(), farg, w_arg)
-            else:
-                # slow way: build a new "ptr to struct" W_CData by calling
-                # the equivalent of ffi.new()
-                if space.is_w(w_arg, space.w_None):
-                    continue
-                w_arg = farg.newp(w_arg)
-            args_w[i] = w_arg
-
-    def descr_call(self, args_w):
-        if len(args_w) != self.nargs_expected:
-            space = self.space
-            if self.nargs_expected == 0:
+        rawfunctype = jit.promote(self.rawfunctype)
+        ctype = rawfunctype.nostruct_ctype
+        locs = rawfunctype.nostruct_locs
+        nargs_expected = rawfunctype.nostruct_nargs
+        #
+        if len(args_w) != nargs_expected:
+            if nargs_expected == 0:
                 raise oefmt(space.w_TypeError,
                             "%s() takes no arguments (%d given)",
                             self.fnname, len(args_w))
-            elif self.nargs_expected == 1:
+            elif nargs_expected == 1:
                 raise oefmt(space.w_TypeError,
                             "%s() takes exactly one argument (%d given)",
                             self.fnname, len(args_w))
             else:
                 raise oefmt(space.w_TypeError,
                             "%s() takes exactly %d arguments (%d given)",
-                            self.fnname, self.nargs_expected, len(args_w))
+                            self.fnname, nargs_expected, len(args_w))
         #
-        if self.locs is not None:
+        if locs is not None:
             # This case is if there are structs as arguments or return values.
             # If the result we want to present to the user is "returns struct",
             # then internally allocate the struct and pass a pointer to it as
             # a first argument.
-            if self.locs[0] == 'R':
-                w_result_cdata = self.ctype.fargs[0].newp(self.space.w_None)
+            if locs[0] == 'R':
+                w_result_cdata = ctype.fargs[0].newp(space.w_None)
                 args_w = [w_result_cdata] + args_w
-                self._prepare(args_w, 1)
-                self.ctype._call(self.fnptr, args_w)    # returns w_None
+                prepare_args(space, rawfunctype, args_w, 1)
+                #
+                ctype._call(self.fnptr, args_w)    # returns w_None
+                #
                 assert isinstance(w_result_cdata, W_CDataPtrToStructOrUnion)
                 return w_result_cdata.structobj
             else:
                 args_w = args_w[:]
-                self._prepare(args_w, 0)
+                prepare_args(space, rawfunctype, args_w, 0)
         #
-        return self.ctype._call(self.fnptr, args_w)
+        return ctype._call(self.fnptr, args_w)
 
     def descr_repr(self, space):
         return space.wrap("<FFIFunctionWrapper for %s()>" % (self.fnname,))
 
 
+ at jit.unroll_safe
+def prepare_args(space, rawfunctype, args_w, start_index):
+    # replaces struct/union arguments with ptr-to-struct/union arguments
+    locs = rawfunctype.nostruct_locs
+    fargs = rawfunctype.nostruct_ctype.fargs
+    for i in range(start_index, len(locs)):
+        if locs[i] != 'A':
+            continue
+        w_arg = args_w[i]
+        farg = fargs[i]      # <ptr to struct/union>
+        assert isinstance(farg, W_CTypePtrOrArray)
+        if isinstance(w_arg, W_CData) and w_arg.ctype is farg.ctitem:
+            # fast way: we are given a W_CData "struct", so just make
+            # a new W_CData "ptr-to-struct" which points to the same
+            # raw memory.  We use unsafe_escaping_ptr(), so we have to
+            # make sure the original 'w_arg' stays alive; the easiest
+            # is to build an instance of W_CDataPtrToStructOrUnion.
+            w_arg = W_CDataPtrToStructOrUnion(
+                space, w_arg.unsafe_escaping_ptr(), farg, w_arg)
+        else:
+            # slow way: build a new "ptr to struct" W_CData by calling
+            # the equivalent of ffi.new()
+            if space.is_w(w_arg, space.w_None):
+                continue
+            w_arg = farg.newp(w_arg)
+        args_w[i] = w_arg
+
+
 W_FunctionWrapper.typedef = TypeDef(
         'FFIFunctionWrapper',
         __repr__ = interp2app(W_FunctionWrapper.descr_repr),
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -613,7 +613,7 @@
 # ____________________________________________________________
 
 def wrap_list_of_str(space, lst):
-    return space.newlist([space.wrap(s) for s in lst])
+    return space.newlist_bytes(lst)
 
 class FileState:
     def __init__(self, space):
diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py
--- a/pypy/module/_io/interp_textio.py
+++ b/pypy/module/_io/interp_textio.py
@@ -600,6 +600,7 @@
 
     def read_w(self, space, w_size=None):
         self._check_attached(space)
+        self._check_closed(space)
         if not self.w_decoder:
             raise OperationError(space.w_IOError, space.wrap("not readable"))
 
@@ -641,6 +642,7 @@
 
     def readline_w(self, space, w_limit=None):
         self._check_attached(space)
+        self._check_closed(space)
         self._writeflush(space)
 
         limit = convert_size(space, w_limit)
@@ -736,7 +738,7 @@
 
     def write_w(self, space, w_text):
         self._check_attached(space)
-        # self._check_closed(space)
+        self._check_closed(space)
 
         if not self.w_encoder:
             raise OperationError(space.w_IOError, space.wrap("not writable"))
diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py
--- a/pypy/module/_io/test/test_io.py
+++ b/pypy/module/_io/test/test_io.py
@@ -391,3 +391,57 @@
             f.seek(1, 0)
             f.read(buffer_size * 2)
             assert f.tell() == 1 + buffer_size * 2
+
+
+class AppTestIoAferClose:
+    spaceconfig = dict(usemodules=['_io'])
+
+    def setup_class(cls):
+        tmpfile = udir.join('tmpfile').ensure()
+        cls.w_tmpfile = cls.space.wrap(str(tmpfile))
+
+    def test_io_after_close(self):
+        import _io
+        for kwargs in [
+                {"mode": "w"},
+                {"mode": "wb"},
+                {"mode": "w", "buffering": 1},
+                {"mode": "w", "buffering": 2},
+                {"mode": "wb", "buffering": 0},
+                {"mode": "r"},
+                {"mode": "rb"},
+                {"mode": "r", "buffering": 1},
+                {"mode": "r", "buffering": 2},
+                {"mode": "rb", "buffering": 0},
+                {"mode": "w+"},
+                {"mode": "w+b"},
+                {"mode": "w+", "buffering": 1},
+                {"mode": "w+", "buffering": 2},
+                {"mode": "w+b", "buffering": 0},
+            ]:
+            print kwargs
+            if "b" not in kwargs["mode"]:
+                kwargs["encoding"] = "ascii"
+            f = _io.open(self.tmpfile, **kwargs)
+            f.close()
+            raises(ValueError, f.flush)
+            raises(ValueError, f.fileno)
+            raises(ValueError, f.isatty)
+            raises(ValueError, f.__iter__)
+            if hasattr(f, "peek"):
+                raises(ValueError, f.peek, 1)
+            raises(ValueError, f.read)
+            if hasattr(f, "read1"):
+                raises(ValueError, f.read1, 1024)
+            if hasattr(f, "readall"):
+                raises(ValueError, f.readall)
+            if hasattr(f, "readinto"):
+                raises(ValueError, f.readinto, bytearray(1024))
+            raises(ValueError, f.readline)
+            raises(ValueError, f.readlines)
+            raises(ValueError, f.seek, 0)
+            raises(ValueError, f.tell)
+            raises(ValueError, f.truncate)
+            raises(ValueError, f.write, b"" if "b" in kwargs['mode'] else u"")
+            raises(ValueError, f.writelines, [])
+            raises(ValueError, next, f)
diff --git a/pypy/module/_rawffi/callback.py b/pypy/module/_rawffi/callback.py
--- a/pypy/module/_rawffi/callback.py
+++ b/pypy/module/_rawffi/callback.py
@@ -27,8 +27,10 @@
     callback_ptr = global_counter.get(userdata.addarg)
     w_callable = callback_ptr.w_callable
     argtypes = callback_ptr.argtypes
+    must_leave = False
     space = callback_ptr.space
     try:
+        must_leave = space.threadlocals.try_enter_thread(space)
         args_w = [None] * len(argtypes)
         for i in range(len(argtypes)):
             argtype = argtypes[i]
@@ -50,6 +52,8 @@
             resshape = letter2tp(space, callback_ptr.result)
             for i in range(resshape.size):
                 ll_res[i] = '\x00'
+    if must_leave:
+        space.threadlocals.leave_thread(space)
 
 class W_CallbackPtr(W_DataInstance):
 
@@ -75,6 +79,14 @@
         if tracker.DO_TRACING:
             addr = rffi.cast(lltype.Signed, self.ll_callback.ll_closure)
             tracker.trace_allocation(addr, self)
+        #
+        # We must setup the GIL here, in case the callback is invoked in
+        # some other non-Pythonic thread.  This is the same as ctypes on
+        # CPython (but only when creating a callback; on CPython it occurs
+        # as soon as we import _ctypes)
+        if space.config.translation.thread:
+            from pypy.module.thread.os_thread import setup_threads
+            setup_threads(space)
 
     def free(self):
         if tracker.DO_TRACING:
diff --git a/pypy/module/_socket/__init__.py b/pypy/module/_socket/__init__.py
--- a/pypy/module/_socket/__init__.py
+++ b/pypy/module/_socket/__init__.py
@@ -18,6 +18,10 @@
         from rpython.rlib.rsocket import rsocket_startup
         rsocket_startup()
 
+    def shutdown(self, space):
+        from pypy.module._socket.interp_socket import close_all_sockets
+        close_all_sockets(space)
+
     def buildloaders(cls):
         from rpython.rlib import rsocket
         for name in """
diff --git a/pypy/module/_socket/interp_func.py b/pypy/module/_socket/interp_func.py
--- a/pypy/module/_socket/interp_func.py
+++ b/pypy/module/_socket/interp_func.py
@@ -142,7 +142,7 @@
         sock = rsocket.fromfd(fd, family, type, proto)
     except SocketError, e:
         raise converted_error(space, e)
-    return space.wrap(W_Socket(sock))
+    return space.wrap(W_Socket(space, sock))
 
 @unwrap_spec(family=int, type=int, proto=int)
 def socketpair(space, family=rsocket.socketpair_default_family,
@@ -160,8 +160,8 @@
     except SocketError, e:
         raise converted_error(space, e)
     return space.newtuple([
-        space.wrap(W_Socket(sock1)),
-        space.wrap(W_Socket(sock2))
+        space.wrap(W_Socket(space, sock1)),
+        space.wrap(W_Socket(space, sock2))
     ])
 
 # The following 4 functions refuse all negative numbers, like CPython 2.6.
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -1,4 +1,5 @@
-from rpython.rlib import rsocket
+import sys
+from rpython.rlib import rsocket, rweaklist
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.rsocket import (
     RSocket, AF_INET, SOCK_STREAM, SocketError, SocketErrorWithErrno,
@@ -153,8 +154,9 @@
 
 
 class W_Socket(W_Root):
-    def __init__(self, sock):
+    def __init__(self, space, sock):
         self.sock = sock
+        register_socket(space, sock)
 
     def get_type_w(self, space):
         return space.wrap(self.sock.type)
@@ -183,7 +185,7 @@
             fd, addr = self.sock.accept()
             sock = rsocket.make_socket(
                 fd, self.sock.family, self.sock.type, self.sock.proto)
-            return space.newtuple([space.wrap(W_Socket(sock)),
+            return space.newtuple([space.wrap(W_Socket(space, sock)),
                                    addr_as_object(addr, sock.fd, space)])
         except SocketError as e:
             raise converted_error(space, e)
@@ -248,7 +250,7 @@
     def dup_w(self, space):
         try:
             sock = self.sock.dup()
-            return W_Socket(sock)
+            return W_Socket(space, sock)
         except SocketError as e:
             raise converted_error(space, e)
 
@@ -592,10 +594,50 @@
         sock = RSocket(family, type, proto)
     except SocketError as e:
         raise converted_error(space, e)
-    W_Socket.__init__(self, sock)
+    W_Socket.__init__(self, space, sock)
     return space.wrap(self)
 descr_socket_new = interp2app(newsocket)
 
+
+# ____________________________________________________________
+# Automatic shutdown()/close()
+
+# On some systems, the C library does not guarantee that when the program
+# finishes, all data sent so far is really sent even if the socket is not
+# explicitly closed.  This behavior has been observed on Windows but not
+# on Linux, so far.
+NEED_EXPLICIT_CLOSE = (sys.platform == 'win32')
+
+class OpenRSockets(rweaklist.RWeakListMixin):
+    pass
+class OpenRSocketsState:
+    def __init__(self, space):
+        self.openrsockets = OpenRSockets()
+        self.openrsockets.initialize()
+
+def getopenrsockets(space):
+    if NEED_EXPLICIT_CLOSE and space.config.translation.rweakref:
+        return space.fromcache(OpenRSocketsState).openrsockets
+    else:
+        return None
+
+def register_socket(space, socket):
+    openrsockets = getopenrsockets(space)
+    if openrsockets is not None:
+        openrsockets.add_handle(socket)
+
+def close_all_sockets(space):
+    openrsockets = getopenrsockets(space)
+    if openrsockets is not None:
+        for sock_wref in openrsockets.get_all_handles():
+            sock = sock_wref()
+            if sock is not None:
+                try:
+                    sock.close()
+                except SocketError:
+                    pass
+
+
 # ____________________________________________________________
 # Error handling
 
diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -309,10 +309,16 @@
 
 
 class AppTestSocket:
+    spaceconfig = dict(usemodules=['_socket', '_weakref', 'struct'])
+
     def setup_class(cls):
         cls.space = space
         cls.w_udir = space.wrap(str(udir))
 
+    def teardown_class(cls):
+        if not cls.runappdirect:
+            cls.space.sys.getmodule('_socket').shutdown(cls.space)
+
     def test_module(self):
         import _socket
         assert _socket.socket.__name__ == 'socket'
@@ -614,6 +620,12 @@
         finally:
             os.chdir(oldcwd)
 
+    def test_automatic_shutdown(self):
+        # doesn't really test anything, but at least should not explode
+        # in close_all_sockets()
+        import _socket
+        self.foo = _socket.socket()
+
 
 class AppTestPacket:
     def setup_class(cls):
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -136,7 +136,7 @@
     def __init__(self, ctx, protos):
         self.protos = protos
         self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
-        NPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self)
+        NPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
 
         # set both server and client callbacks, because the context
         # can be used to create both types of sockets
@@ -151,7 +151,7 @@
 
     @staticmethod
     def advertiseNPN_cb(s, data_ptr, len_ptr, args):
-        npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+        npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
         if npn and npn.protos:
             data_ptr[0] = npn.buf
             len_ptr[0] = rffi.cast(rffi.UINT, len(npn.protos))
@@ -163,7 +163,7 @@
 
     @staticmethod
     def selectNPN_cb(s, out_ptr, outlen_ptr, server, server_len, args):
-        npn = NPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+        npn = NPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
         if npn and npn.protos:
             client = npn.buf
             client_len = len(npn.protos)
@@ -182,7 +182,7 @@
     def __init__(self, ctx, protos):
         self.protos = protos
         self.buf, self.pinned, self.is_raw = rffi.get_nonmovingbuffer(protos)
-        ALPN_STORAGE.set(r_uint(rffi.cast(rffi.UINT, self.buf)), self)
+        ALPN_STORAGE.set(rffi.cast(lltype.Unsigned, self.buf), self)
 
         with rffi.scoped_str2charp(protos) as protos_buf:
             if libssl_SSL_CTX_set_alpn_protos(
@@ -197,7 +197,7 @@
 
     @staticmethod
     def selectALPN_cb(s, out_ptr, outlen_ptr, client, client_len, args):
-        alpn = ALPN_STORAGE.get(r_uint(rffi.cast(rffi.UINT, args)))
+        alpn = ALPN_STORAGE.get(rffi.cast(lltype.Unsigned, args))
         if alpn and alpn.protos:
             server = alpn.buf
             server_len = len(alpn.protos)
diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -26,7 +26,7 @@
 eci_kwds = dict(
     include_dirs = [SRC],
     includes = ['vmprof.h', 'trampoline.h'],
-    separate_module_files = [SRC.join('trampoline.asmgcc.s')],
+    separate_module_files = [SRC.join('trampoline.vmprof.s')],
     libraries = ['dl'],
     
     post_include_bits=["""
diff --git a/pypy/module/_vmprof/src/trampoline.asmgcc.s b/pypy/module/_vmprof/src/trampoline.vmprof.s
rename from pypy/module/_vmprof/src/trampoline.asmgcc.s
rename to pypy/module/_vmprof/src/trampoline.vmprof.s
--- a/pypy/module/_vmprof/src/trampoline.asmgcc.s
+++ b/pypy/module/_vmprof/src/trampoline.vmprof.s
@@ -1,7 +1,6 @@
 // NOTE: you need to use TABs, not spaces!
         
 	.text
-	.p2align 4,,-1
 	.globl	pypy_execute_frame_trampoline
 	.type	pypy_execute_frame_trampoline, @function
 pypy_execute_frame_trampoline:
diff --git a/pypy/module/_vmprof/src/vmprof.c b/pypy/module/_vmprof/src/vmprof.c
--- a/pypy/module/_vmprof/src/vmprof.c
+++ b/pypy/module/_vmprof/src/vmprof.c
@@ -305,7 +305,6 @@
 
 static int remove_sigprof_timer(void) {
     static struct itimerval timer;
-    last_period_usec = 0;
     timer.it_interval.tv_sec = 0;
     timer.it_interval.tv_usec = 0;
     timer.it_value.tv_sec = 0;
@@ -317,11 +316,15 @@
 }
 
 static void atfork_disable_timer(void) {
-    remove_sigprof_timer();
+    if (last_period_usec) {
+        remove_sigprof_timer();
+    }
 }
 
 static void atfork_enable_timer(void) {
-    install_sigprof_timer(last_period_usec);
+    if (last_period_usec) {
+        install_sigprof_timer(last_period_usec);
+    }
 }
 
 static int install_pthread_atfork_hooks(void) {
@@ -412,6 +415,7 @@
     if (remove_sigprof_timer() == -1) {
 		return -1;
 	}
+    last_period_usec = 0;
     if (remove_sigprof_handler() == -1) {
 		return -1;
 	}
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -38,4 +38,4 @@
     'C') or Fortran-style (fortran is 'F') contiguous or either one
     (fortran is 'A').  Return 0 otherwise."""
     # PyPy only supports contiguous Py_buffers for now.
-    return space.wrap(1)
+    return 1
diff --git a/pypy/module/cpyext/test/test_version.py b/pypy/module/cpyext/test/test_version.py
--- a/pypy/module/cpyext/test/test_version.py
+++ b/pypy/module/cpyext/test/test_version.py
@@ -16,7 +16,7 @@
         }
         """
         module = self.import_module(name='foo', init=init)
-        assert module.py_version == sys.version[:5]
+        assert module.py_version == '%d.%d.%d' % sys.version_info[:3]
         assert module.py_major_version == sys.version_info.major
         assert module.py_minor_version == sys.version_info.minor
         assert module.py_micro_version == sys.version_info.micro
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -349,6 +349,11 @@
                 w_all = try_getattr(space, w_mod, space.wrap('__all__'))
                 if w_all is not None:
                     fromlist_w = space.fixedview(w_all)
+                else:
+                    fromlist_w = []
+                    # "from x import *" with x already imported and no x.__all__
+                    # always succeeds without doing more imports.  It will
+                    # just copy everything from x.__dict__ as it is now.
             for w_name in fromlist_w:
                 if try_getattr(space, w_mod, w_name) is None:
                     return None
@@ -389,6 +394,8 @@
                 w_all = try_getattr(space, w_mod, w('__all__'))
                 if w_all is not None:
                     fromlist_w = space.fixedview(w_all)
+                else:
+                    fromlist_w = []
             for w_name in fromlist_w:
                 if try_getattr(space, w_mod, w_name) is None:
                     load_part(space, w_path, prefix, space.str0_w(w_name),
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -66,6 +66,14 @@
              b          = "insubpackage = 1",
              )
     setuppkg("pkg.pkg2", a='', b='')
+    setuppkg("pkg.withall",
+             __init__  = "__all__ = ['foobar']",
+             foobar    = "found = 123")
+    setuppkg("pkg.withoutall",
+             __init__  = "",
+             foobar    = "found = 123")
+    setuppkg("pkg.bogusall",
+             __init__  = "__all__ = 42")
     setuppkg("pkg_r", inpkg = "import x.y")
     setuppkg("pkg_r.x")
     setuppkg("x", y='')
@@ -677,6 +685,32 @@
         import imp
         raises(ValueError, imp.load_module, "", "", "", [1, 2, 3, 4])
 
+    def test_import_star_finds_submodules_with___all__(self):
+        for case in ["not-imported-yet", "already-imported"]:
+            d = {}
+            exec "from pkg.withall import *" in d
+            assert d["foobar"].found == 123


More information about the pypy-commit mailing list