Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r86855:83f439eeb461 Date: 2016-09-03 12:07 -0700 http://bitbucket.org/pypy/pypy/changeset/83f439eeb461/
Log: merge default diff --git a/_pytest/python.py b/_pytest/python.py --- a/_pytest/python.py +++ b/_pytest/python.py @@ -498,7 +498,10 @@ """ Collector for test methods. """ def collect(self): if hasinit(self.obj): - pytest.skip("class %s.%s with __init__ won't get collected" % ( + # XXX used to be skip(), but silently skipping classes + # XXX just because they have been written long ago is + # XXX imho a very, very, very bad idea + pytest.fail("class %s.%s with __init__ won't get collected" % ( self.obj.__module__, self.obj.__name__, )) 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.8.0 +Version: 1.8.1 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.8.0" -__version_info__ = (1, 8, 0) +__version__ = "1.8.1" +__version_info__ = (1, 8, 1) # 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/_cffi_include.h b/lib_pypy/cffi/_cffi_include.h --- a/lib_pypy/cffi/_cffi_include.h +++ b/lib_pypy/cffi/_cffi_include.h @@ -1,4 +1,20 @@ #define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. +*/ +#ifndef _CFFI_USE_EMBEDDING +# include <pyconfig.h> +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) +# define Py_LIMITED_API +# endif +#endif + #include <Python.h> #ifdef __cplusplus extern "C" { diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.8.0" + "\ncompiled with cffi version: 1.8.1" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); 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 @@ -652,7 +652,7 @@ recompile(self, module_name, source, c_file=filename, call_c_compiler=False, **kwds) - def compile(self, tmpdir='.', verbose=0, target=None): + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): """The 'target' argument gives the final file name of the compiled DLL. Use '*' to force distutils' choice, suitable for regular CPython C API modules. Use a file name ending in '.*' @@ -669,7 +669,7 @@ module_name, source, source_extension, kwds = self._assigned_source return recompile(self, module_name, source, tmpdir=tmpdir, target=target, source_extension=source_extension, - compiler_verbose=verbose, **kwds) + compiler_verbose=verbose, debug=debug, **kwds) def init_once(self, func, tag): # Read _init_once_cache[tag], which is either (False, lock) if diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -997,29 +997,37 @@ assert onerror is None # XXX not implemented return BType(source, error) + _weakref_cache_ref = None + def gcp(self, cdata, destructor): - BType = self.typeof(cdata) + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref if destructor is None: - if not (hasattr(BType, '_gcp_type') and - BType._gcp_type is BType): + try: + del weak_cache[MyRef(cdata)] + except KeyError: raise TypeError("Can remove destructor only on a object " "previously returned by ffi.gc()") - cdata._destructor = None return None - try: - gcp_type = BType._gcp_type - except AttributeError: - class CTypesDataGcp(BType): - __slots__ = ['_orig', '_destructor'] - def __del__(self): - if self._destructor is not None: - self._destructor(self._orig) - gcp_type = BType._gcp_type = CTypesDataGcp - new_cdata = self.cast(gcp_type, cdata) - new_cdata._orig = cdata - new_cdata._destructor = destructor + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) return new_cdata typeof = type diff --git a/lib_pypy/cffi/ffiplatform.py b/lib_pypy/cffi/ffiplatform.py --- a/lib_pypy/cffi/ffiplatform.py +++ b/lib_pypy/cffi/ffiplatform.py @@ -21,12 +21,12 @@ allsources.append(os.path.normpath(src)) return Extension(name=modname, sources=allsources, **kwds) -def compile(tmpdir, ext, compiler_verbose=0): +def compile(tmpdir, ext, compiler_verbose=0, debug=None): """Compile a C extension module using distutils.""" saved_environ = os.environ.copy() try: - outputfilename = _build(tmpdir, ext, compiler_verbose) + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) outputfilename = os.path.abspath(outputfilename) finally: # workaround for a distutils bugs where some env vars can @@ -36,7 +36,7 @@ os.environ[key] = value return outputfilename -def _build(tmpdir, ext, compiler_verbose=0): +def _build(tmpdir, ext, compiler_verbose=0, debug=None): # XXX compact but horrible :-( from distutils.core import Distribution import distutils.errors, distutils.log @@ -44,6 +44,9 @@ dist = Distribution({'ext_modules': [ext]}) dist.parse_config_files() options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) options['force'] = ('ffiplatform', True) options['build_lib'] = ('ffiplatform', tmpdir) options['build_temp'] = ('ffiplatform', tmpdir) 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 @@ -275,8 +275,8 @@ def write_c_source_to_f(self, f, preamble): self._f = f prnt = self._prnt - if self.ffi._embedding is None: - prnt('#define Py_LIMITED_API') + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') # # first the '#include' (actually done by inlining the file's content) lines = self._rel_readlines('_cffi_include.h') @@ -1431,7 +1431,7 @@ def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, c_file=None, source_extension='.c', extradir=None, - compiler_verbose=1, target=None, **kwds): + compiler_verbose=1, target=None, debug=None, **kwds): if not isinstance(module_name, str): module_name = module_name.encode('ascii') if ffi._windows_unicode: @@ -1467,7 +1467,8 @@ if target != '*': _patch_for_target(patchlist, target) os.chdir(tmpdir) - outputfilename = ffiplatform.compile('.', ext, compiler_verbose) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) finally: os.chdir(cwd) _unpatch_meths(patchlist) diff --git a/lib_pypy/cffi/setuptools_ext.py b/lib_pypy/cffi/setuptools_ext.py --- a/lib_pypy/cffi/setuptools_ext.py +++ b/lib_pypy/cffi/setuptools_ext.py @@ -69,16 +69,36 @@ else: _add_c_module(dist, ffi, module_name, source, source_extension, kwds) +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + """ + if 'py_limited_api' not in kwds: + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): from distutils.core import Extension - from distutils.command.build_ext import build_ext + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext from distutils.dir_util import mkpath from distutils import log from cffi import recompiler allsources = ['$PLACEHOLDER'] allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) ext = Extension(name=module_name, sources=allsources, **kwds) def make_mod(tmpdir, pre_run=None): 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 @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi, entrypoint from rpython.rtyper.lltypesystem import rffi -VERSION = "1.8.0" +VERSION = "1.8.1" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: 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 @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.8.0", ("This test_c.py file is for testing a version" +assert __version__ == "1.8.1", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py --- a/pypy/module/pypyjit/test_pypy_c/test_instance.py +++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py @@ -187,6 +187,43 @@ """) + def test_oldstyle_methcall(self): + def main(): + def g(): pass + class A: + def f(self): + return self.x + 1 + class I(A): + pass + class J(I): + pass + + + class B(J): + def __init__(self, x): + self.x = x + + i = 0 + b = B(1) + while i < 1000: + g() + v = b.f() # ID: meth + i += v + return i + + log = self.run(main, [], threshold=80) + loop, = log.loops_by_filename(self.filepath, is_entry_bridge=True) + assert loop.match_by_id('meth', + ''' + guard_nonnull_class(p18, ..., descr=...) + p52 = getfield_gc_r(p18, descr=...) # read map + guard_value(p52, ConstPtr(ptr53), descr=...) + p54 = getfield_gc_r(p18, descr=...) # read class + guard_value(p54, ConstPtr(ptr55), descr=...) + p56 = force_token() # done + ''') + + def test_oldstyle_newstyle_mix(self): def main(): class A: diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py @@ -1479,6 +1479,7 @@ assert p1[0] == 123 seen.append(1) q = ffi.gc(p, destructor) + assert ffi.typeof(q) is ffi.typeof(p) import gc; gc.collect() assert seen == [] del q diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_zintegration.py @@ -149,3 +149,25 @@ p = snip_setuptools_verify2.C.getpwuid(0) assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root" ''') + + def test_set_py_limited_api(self): + from cffi.setuptools_ext import _set_py_limited_api + try: + import setuptools + orig_version = setuptools.__version__ + setuptools.__version__ = '26.0.0' + from setuptools import Extension + + kwds = _set_py_limited_api(Extension, {}) + assert kwds['py_limited_api'] == True + + setuptools.__version__ = '25.0' + kwds = _set_py_limited_api(Extension, {}) + assert not kwds + + setuptools.__version__ = 'development' + kwds = _set_py_limited_api(Extension, {}) + assert kwds['py_limited_api'] == True + + finally: + setuptools.__version__ = orig_version diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py --- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py +++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_recompiler.py @@ -1975,9 +1975,9 @@ def test_function_returns_partial_struct(): ffi = FFI() - ffi.cdef("struct a { int a; ...; }; struct a f1(int);") + ffi.cdef("struct aaa { int a; ...; }; struct aaa f1(int);") lib = verify(ffi, "test_function_returns_partial_struct", """ - struct a { int b, a, c; }; - static struct a f1(int x) { struct a s = {0}; s.a = x; return s; } + struct aaa { int b, a, c; }; + static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; } """) assert lib.f1(52).a == 52 diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_numbers.py @@ -194,6 +194,29 @@ _fields_ = [('t', enum)] assert isinstance(S().t, enum) + def test_no_missing_shape_to_ffi_type(self): + # whitebox test + import sys + if '__pypy__' not in sys.builtin_module_names: + skip("only for pypy's ctypes") + skip("re-enable after adding 'g' to _shape_to_ffi_type.typemap, " + "which I think needs fighting all the way up from " + "rpython.rlib.libffi") + from _ctypes.basics import _shape_to_ffi_type + from _rawffi import Array + for i in range(1, 256): + try: + Array(chr(i)) + except ValueError: + pass + else: + assert chr(i) in _shape_to_ffi_type.typemap + + @py.test.mark.xfail + def test_pointer_to_long_double(self): + import ctypes + ctypes.POINTER(ctypes.c_longdouble) + ## def test_perf(self): ## check_perf() diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py --- a/rpython/annotator/annrpython.py +++ b/rpython/annotator/annrpython.py @@ -164,8 +164,15 @@ # annotations that are passed in, and don't annotate the old # graph -- it's already low-level operations! for a, s_newarg in zip(block.inputargs, cells): - s_oldarg = self.binding(a) - assert annmodel.unionof(s_oldarg, s_newarg) == s_oldarg + s_oldarg = a.annotation + # XXX: Should use s_oldarg.contains(s_newarg) but that breaks + # PyPy translation + if annmodel.unionof(s_oldarg, s_newarg) != s_oldarg: + raise annmodel.AnnotatorError( + "Late-stage annotation is not allowed to modify the " + "existing annotation for variable %s: %s" % + (a, s_oldarg)) + else: assert not self.frozen if block not in self.annotated: diff --git a/rpython/annotator/binaryop.py b/rpython/annotator/binaryop.py --- a/rpython/annotator/binaryop.py +++ b/rpython/annotator/binaryop.py @@ -17,7 +17,7 @@ from rpython.flowspace.model import Variable, Constant, const from rpython.flowspace.operation import op from rpython.rlib import rarithmetic -from rpython.annotator.model import AnnotatorError +from rpython.annotator.model import AnnotatorError, TLS BINARY_OPERATIONS = set([oper.opname for oper in op.__dict__.values() if oper.dispatch == 2]) @@ -436,6 +436,11 @@ class __extend__(pairtype(SomeFloat, SomeFloat)): def union((flt1, flt2)): + if not TLS.allow_int_to_float: + # in this mode, if one of the two is actually the + # subclass SomeInteger, complain + if isinstance(flt1, SomeInteger) or isinstance(flt2, SomeInteger): + raise UnionError(flt1, flt2) return SomeFloat() add = sub = mul = union diff --git a/rpython/annotator/model.py b/rpython/annotator/model.py --- a/rpython/annotator/model.py +++ b/rpython/annotator/model.py @@ -44,6 +44,7 @@ # A global attribute :-( Patch it with 'True' to enable checking of # the no_nul attribute... check_str_without_nul = False + allow_int_to_float = True TLS = State() class SomeObject(object): @@ -749,6 +750,7 @@ s1 = pair(s1, s2).union() else: # this is just a performance shortcut + # XXX: This is a lie! Grep for no_side_effects_in_union and weep. if s1 != s2: s1 = pair(s1, s2).union() return s1 diff --git a/rpython/rlib/libffi.py b/rpython/rlib/libffi.py --- a/rpython/rlib/libffi.py +++ b/rpython/rlib/libffi.py @@ -47,6 +47,8 @@ cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG) cls.signed = clibffi.cast_type_to_ffitype(rffi.SIGNED) cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar) + # XXX long double support: clibffi.ffi_type_longdouble, but then + # XXX fix the whole rest of this file to add a case for long double del cls._import @staticmethod diff --git a/rpython/rlib/rdynload.py b/rpython/rlib/rdynload.py --- a/rpython/rlib/rdynload.py +++ b/rpython/rlib/rdynload.py @@ -98,8 +98,15 @@ try: ctypes.CDLL(name) except OSError as e: + # common case: ctypes fails too, with the real dlerror() + # message in str(e). Return that error message. return str(e) else: + # uncommon case: may happen if 'name' is a linker script + # (which the C-level dlopen() can't handle) and we are + # directly running on pypy (whose implementation of ctypes + # or cffi will resolve linker scripts). In that case, + # unsure what we can do. return ("opening %r with ctypes.CDLL() works, " "but not with c_dlopen()??" % (name,)) @@ -160,7 +167,18 @@ mode = _dlopen_default_mode() elif (mode & (RTLD_LAZY | RTLD_NOW)) == 0: mode |= RTLD_NOW + # + # haaaack for 'pypy py.test -A' if libm.so is a linker script + # (see reason in _dlerror_on_dlopen_untranslated()) + must_free = False + if not we_are_translated() and platform.name == "linux": + if name and rffi.charp2str(name) == 'libm.so': + name = rffi.str2charp('libm.so.6') + must_free = True + # res = c_dlopen(name, rffi.cast(rffi.INT, mode)) + if must_free: + rffi.free_charp(name) if not res: if not we_are_translated(): err = _dlerror_on_dlopen_untranslated(name) diff --git a/rpython/rlib/rmarshal.py b/rpython/rlib/rmarshal.py --- a/rpython/rlib/rmarshal.py +++ b/rpython/rlib/rmarshal.py @@ -346,11 +346,15 @@ # on s_bigger. It relies on the fact that s_bigger was created with # an expression like 'annotation([s_item])' which returns a ListDef with # no bookkeeper, on which side-effects are not allowed. + saved = annmodel.TLS.allow_int_to_float try: + annmodel.TLS.allow_int_to_float = False s_union = annmodel.unionof(s_bigger, s_smaller) return s_bigger.contains(s_union) except (annmodel.UnionError, TooLateForChange): return False + finally: + annmodel.TLS.allow_int_to_float = saved class __extend__(pairtype(MTag, annmodel.SomeObject)): diff --git a/rpython/rlib/runicode.py b/rpython/rlib/runicode.py --- a/rpython/rlib/runicode.py +++ b/rpython/rlib/runicode.py @@ -137,7 +137,27 @@ result=result) return result.build(), pos -@specialize.argtype(6) +def _invalid_cont_byte(ordch): + return ordch>>6 != 0x2 # 0b10 + +_invalid_byte_2_of_2 = _invalid_cont_byte +_invalid_byte_3_of_3 = _invalid_cont_byte +_invalid_byte_3_of_4 = _invalid_cont_byte +_invalid_byte_4_of_4 = _invalid_cont_byte + +@specialize.arg(2) +def _invalid_byte_2_of_3(ordch1, ordch2, allow_surrogates): + return (ordch2>>6 != 0x2 or # 0b10 + (ordch1 == 0xe0 and ordch2 < 0xa0) + # surrogates shouldn't be valid UTF-8! + or (not allow_surrogates and ordch1 == 0xed and ordch2 > 0x9f)) + +def _invalid_byte_2_of_4(ordch1, ordch2): + return (ordch2>>6 != 0x2 or # 0b10 + (ordch1 == 0xf0 and ordch2 < 0x90) or + (ordch1 == 0xf4 and ordch2 > 0x8f)) + +@specialize.arg(5) def str_decode_utf_8_impl(s, size, errors, final, errorhandler, allow_surrogates, result): if size == 0: @@ -157,22 +177,23 @@ if pos + n > size: if not final: break + # argh, this obscure block of code is mostly a copy of + # what follows :-( charsleft = size - pos - 1 # either 0, 1, 2 - # note: when we get the 'unexpected end of data' we don't care - # about the pos anymore and we just ignore the value + # note: when we get the 'unexpected end of data' we need + # to care about the pos returned; it can be lower than size, + # in case we need to continue running this loop if not charsleft: # there's only the start byte and nothing else r, pos = errorhandler(errors, 'utf8', 'unexpected end of data', s, pos, pos+1) result.append(r) - break + continue ordch2 = ord(s[pos+1]) if n == 3: # 3-bytes seq with only a continuation byte - if (ordch2>>6 != 0x2 or # 0b10 - (ordch1 == 0xe0 and ordch2 < 0xa0)): - # or (ordch1 == 0xed and ordch2 > 0x9f) + if _invalid_byte_2_of_3(ordch1, ordch2, allow_surrogates): # second byte invalid, take the first and continue r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', @@ -185,19 +206,17 @@ 'unexpected end of data', s, pos, pos+2) result.append(r) - break + continue elif n == 4: # 4-bytes seq with 1 or 2 continuation bytes - if (ordch2>>6 != 0x2 or # 0b10 - (ordch1 == 0xf0 and ordch2 < 0x90) or - (ordch1 == 0xf4 and ordch2 > 0x8f)): + if _invalid_byte_2_of_4(ordch1, ordch2): # second byte invalid, take the first and continue r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+1) result.append(r) continue - elif charsleft == 2 and ord(s[pos+2])>>6 != 0x2: # 0b10 + elif charsleft == 2 and _invalid_byte_3_of_4(ord(s[pos+2])): # third byte invalid, take the first two and continue r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', @@ -210,7 +229,8 @@ 'unexpected end of data', s, pos, pos+charsleft+1) result.append(r) - break + continue + raise AssertionError("unreachable") if n == 0: r, pos = errorhandler(errors, 'utf8', @@ -223,7 +243,7 @@ elif n == 2: ordch2 = ord(s[pos+1]) - if ordch2>>6 != 0x2: # 0b10 + if _invalid_byte_2_of_2(ordch2): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+1) @@ -237,17 +257,13 @@ elif n == 3: ordch2 = ord(s[pos+1]) ordch3 = ord(s[pos+2]) - if (ordch2>>6 != 0x2 or # 0b10 - (ordch1 == 0xe0 and ordch2 < 0xa0) - # surrogates shouldn't be valid UTF-8! - or (not allow_surrogates and ordch1 == 0xed and ordch2 > 0x9f) - ): + if _invalid_byte_2_of_3(ordch1, ordch2, allow_surrogates): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+1) result.append(r) continue - elif ordch3>>6 != 0x2: # 0b10 + elif _invalid_byte_3_of_3(ordch3): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+2) @@ -263,21 +279,19 @@ ordch2 = ord(s[pos+1]) ordch3 = ord(s[pos+2]) ordch4 = ord(s[pos+3]) - if (ordch2>>6 != 0x2 or # 0b10 - (ordch1 == 0xf0 and ordch2 < 0x90) or - (ordch1 == 0xf4 and ordch2 > 0x8f)): + if _invalid_byte_2_of_4(ordch1, ordch2): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+1) result.append(r) continue - elif ordch3>>6 != 0x2: # 0b10 + elif _invalid_byte_3_of_4(ordch3): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+2) result.append(r) continue - elif ordch4>>6 != 0x2: # 0b10 + elif _invalid_byte_4_of_4(ordch4): r, pos = errorhandler(errors, 'utf8', 'invalid continuation byte', s, pos, pos+3) diff --git a/rpython/rlib/test/test_rmarshal.py b/rpython/rlib/test/test_rmarshal.py --- a/rpython/rlib/test/test_rmarshal.py +++ b/rpython/rlib/test/test_rmarshal.py @@ -128,10 +128,12 @@ def test_llinterp_marshal(): from rpython.rtyper.test.test_llinterp import interpret - marshaller = get_marshaller([(int, str, float)]) + marshaller1 = get_marshaller([(int, str, float)]) + marshaller2 = get_marshaller([(int, str, int)]) def f(): buf = [] - marshaller(buf, [(5, "hello", -0.5), (7, "world", 1E100)]) + marshaller1(buf, [(5, "hello", -0.5), (7, "world", 1E100)]) + marshaller2(buf, [(5, "hello", 1)]) return ''.join(buf) res = interpret(f, []) res = ''.join(res.chars) @@ -139,14 +141,20 @@ assert res == ('[\x02\x00\x00\x00(\x03\x00\x00\x00i\x05\x00\x00\x00' 's\x05\x00\x00\x00hellof\x04-0.5(\x03\x00\x00\x00' 'i\x07\x00\x00\x00s\x05\x00\x00\x00world' - 'f\x061e+100') + 'f\x061e+100' + '[\x01\x00\x00\x00(\x03\x00\x00\x00i\x05\x00\x00\x00' + 's\x05\x00\x00\x00helloi\x01\x00\x00\x00') else: assert res == ('[\x02\x00\x00\x00(\x03\x00\x00\x00' 'I\x05\x00\x00\x00\x00\x00\x00\x00' 's\x05\x00\x00\x00hellof\x04-0.5(\x03\x00\x00\x00' 'I\x07\x00\x00\x00\x00\x00\x00\x00' 's\x05\x00\x00\x00world' - 'f\x061e+100') + 'f\x061e+100' + '[\x01\x00\x00\x00(\x03\x00\x00\x00' + 'I\x05\x00\x00\x00\x00\x00\x00\x00' + 's\x05\x00\x00\x00hello' + 'I\x01\x00\x00\x00\x00\x00\x00\x00') def test_llinterp_unmarshal(): from rpython.rtyper.test.test_llinterp import interpret diff --git a/rpython/rlib/test/test_runicode.py b/rpython/rlib/test/test_runicode.py --- a/rpython/rlib/test/test_runicode.py +++ b/rpython/rlib/test/test_runicode.py @@ -286,9 +286,15 @@ class TestUTF8Decoding(UnicodeTests): - def __init__(self): + def setup_method(self, meth): self.decoder = self.getdecoder('utf-8') + def custom_replace(self, errors, encoding, msg, s, startingpos, endingpos): + assert errors == 'custom' + # returns FOO, but consumes only one character (not up to endingpos) + FOO = u'\u1234' + return FOO, startingpos + 1 + def to_bytestring(self, bytes): return ''.join(chr(int(c, 16)) for c in bytes.split()) @@ -309,6 +315,7 @@ E.g. <80> is a continuation byte and can appear only after a start byte. """ FFFD = u'\ufffd' + FOO = u'\u1234' for byte in '\x80\xA0\x9F\xBF\xC0\xC1\xF5\xFF': py.test.raises(UnicodeDecodeError, self.decoder, byte, 1, None, final=True) self.checkdecodeerror(byte, 'utf-8', 0, 1, addstuff=False, @@ -320,6 +327,11 @@ assert self.decoder(byte, 1, 'ignore', final=True) == (u'', 1) assert (self.decoder('aaaa' + byte + 'bbbb', 9, 'ignore', final=True) == (u'aaaabbbb', 9)) + assert self.decoder(byte, 1, 'custom', final=True, + errorhandler=self.custom_replace) == (FOO, 1) + assert (self.decoder('aaaa' + byte + 'bbbb', 9, 'custom', + final=True, errorhandler=self.custom_replace) == + (u'aaaa'+ FOO + u'bbbb', 9)) def test_unexpected_end_of_data(self): """ @@ -343,6 +355,7 @@ 'F4 80', 'F4 8F', 'F4 80 80', 'F4 80 BF', 'F4 8F 80', 'F4 8F BF' ] FFFD = u'\ufffd' + FOO = u'\u1234' for seq in sequences: seq = self.to_bytestring(seq) py.test.raises(UnicodeDecodeError, self.decoder, seq, len(seq), @@ -358,6 +371,12 @@ ) == (u'', len(seq)) assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, 'ignore', final=True) == (u'aaaabbbb', len(seq) + 8)) + assert (self.decoder(seq, len(seq), 'custom', final=True, + errorhandler=self.custom_replace) == + (FOO * len(seq), len(seq))) + assert (self.decoder('aaaa' + seq + 'bbbb', len(seq) + 8, 'custom', + final=True, errorhandler=self.custom_replace) == + (u'aaaa'+ FOO * len(seq) + u'bbbb', len(seq) + 8)) def test_invalid_cb_for_2bytes_seq(self): """ diff --git a/rpython/rtyper/lltypesystem/test/test_rffi.py b/rpython/rtyper/lltypesystem/test/test_rffi.py --- a/rpython/rtyper/lltypesystem/test/test_rffi.py +++ b/rpython/rtyper/lltypesystem/test/test_rffi.py @@ -38,6 +38,24 @@ xf = self.compile(f, []) assert xf() == 8+3 + def test_no_float_to_int_conversion(self): + c_source = py.code.Source(""" + int someexternalfunction(int x) + { + return (x + 3); + } + """) + + eci = ExternalCompilationInfo(separate_module_sources=[c_source]) + z = llexternal('someexternalfunction', [Signed], Signed, + compilation_info=eci) + + def f(): + return z(8.2) + + py.test.raises(TypeError, f) + py.test.raises(TypeError, self.compile, f, []) + def test_hashdefine(self): h_source = """ #define X(i) (i+3) diff --git a/rpython/rtyper/rint.py b/rpython/rtyper/rint.py --- a/rpython/rtyper/rint.py +++ b/rpython/rtyper/rint.py @@ -540,7 +540,7 @@ def ll_ullong_py_mod_zer(x, y): if y == 0: raise ZeroDivisionError - return llop.ullong_mod(UnsignedLongLong, x, y) + return ll_ullong_py_mod(x, y) @jit.dont_look_inside def ll_lllong_py_mod(x, y): diff --git a/rpython/translator/backendopt/inline.py b/rpython/translator/backendopt/inline.py --- a/rpython/translator/backendopt/inline.py +++ b/rpython/translator/backendopt/inline.py @@ -532,8 +532,7 @@ return sys.maxint else: res = Solution[blockmap[graph.startblock]] - assert res >= 0 - return res + return max(res, 0.0) def static_instruction_count(graph): count = 0 diff --git a/rpython/translator/c/test/test_exception.py b/rpython/translator/c/test/test_exception.py --- a/rpython/translator/c/test/test_exception.py +++ b/rpython/translator/c/test/test_exception.py @@ -9,7 +9,7 @@ getcompiledopt = test_backendoptimized.TestTypedOptimizedTestCase().getcompiled -class TestException(Exception): +class InTestException(Exception): pass class MyException(Exception): @@ -18,7 +18,7 @@ def test_simple1(): def raise_(i): if i == 0: - raise TestException() + raise InTestException() elif i == 1: raise MyException() else: @@ -29,7 +29,7 @@ b = raise_(i) + 12 c = raise_(i) + 13 return a+b+c - except TestException: + except InTestException: return 7 except MyException: return 123 diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -213,6 +213,7 @@ log.WARNING(warning) def main(): + sys.setrecursionlimit(2000) # PyPy can't translate within cpython's 1k limit targetspec_dic, translateconfig, config, args = parse_options_and_load_target() from rpython.translator import translator from rpython.translator import driver diff --git a/rpython/translator/sandbox/test/test_sandbox.py b/rpython/translator/sandbox/test/test_sandbox.py --- a/rpython/translator/sandbox/test/test_sandbox.py +++ b/rpython/translator/sandbox/test/test_sandbox.py @@ -29,6 +29,7 @@ assert msg == fnname msg = read_message(f) assert msg == args + assert [type(x) for x in msg] == [type(x) for x in args] if isinstance(result, Exception): write_exception(g, result) else: _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit