Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r45894:48020b9e373b Date: 2011-07-23 11:00 +0200 http://bitbucket.org/pypy/pypy/changeset/48020b9e373b/
Log: On CPython, some functions accept integers of any size and truncate. This seems to be important at least for crc32() and adler32(), so fix it for them. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1284,6 +1284,17 @@ self.wrap("expected a 32-bit integer")) return value + def truncatedint(self, w_obj): + # Like space.gateway_int_w(), but return the integer truncated + # instead of raising OverflowError. For obscure cases only. + try: + return self.int_w(w_obj) + except OperationError, e: + if not e.match(self, self.w_OverflowError): + raise + from pypy.rlib.rarithmetic import intmask + return intmask(self.bigint_w(w_obj).uintmask()) + def c_filedescriptor_w(self, w_fd): # This is only used sometimes in CPython, e.g. for os.fsync() but # not os.close(). It's likely designed for 'select'. It's irregular diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -140,6 +140,9 @@ def visit_c_nonnegint(self, el, app_sig): self.checked_space_method(el, app_sig) + def visit_truncatedint(self, el, app_sig): + self.checked_space_method(el, app_sig) + def visit__Wrappable(self, el, app_sig): name = el.__name__ argname = self.orig_arg() @@ -257,6 +260,9 @@ def visit_c_nonnegint(self, typ): self.run_args.append("space.c_nonnegint_w(%s)" % (self.scopenext(),)) + def visit_truncatedint(self, typ): + self.run_args.append("space.truncatedint(%s)" % (self.scopenext(),)) + def _make_unwrap_activation_class(self, unwrap_spec, cache={}): try: key = tuple(unwrap_spec) @@ -387,6 +393,9 @@ def visit_c_nonnegint(self, typ): self.unwrap.append("space.c_nonnegint_w(%s)" % (self.nextarg(),)) + def visit_truncatedint(self, typ): + self.unwrap.append("space.truncatedint(%s)" % (self.nextarg(),)) + def make_fastfunc(unwrap_spec, func): unwrap_info = UnwrapSpec_FastFunc_Unwrap() unwrap_info.apply_over(unwrap_spec) diff --git a/pypy/module/binascii/interp_crc32.py b/pypy/module/binascii/interp_crc32.py --- a/pypy/module/binascii/interp_crc32.py +++ b/pypy/module/binascii/interp_crc32.py @@ -61,7 +61,7 @@ crc_32_tab = map(r_uint, crc_32_tab) -@unwrap_spec(data='bufferstr', oldcrc='c_int') +@unwrap_spec(data='bufferstr', oldcrc='truncatedint') def crc32(space, data, oldcrc=0): "Compute the CRC-32 incrementally." diff --git a/pypy/module/binascii/test/test_binascii.py b/pypy/module/binascii/test/test_binascii.py --- a/pypy/module/binascii/test/test_binascii.py +++ b/pypy/module/binascii/test/test_binascii.py @@ -374,6 +374,8 @@ ('x', 10000, -1855256896), ('y', 10000, -429115818), ('z', 10000, 2137352172), + ('foo', 99999999999999999999999999, -1932704816), + ('bar', -99999999999999999999999999, 2000545409), ]: assert self.binascii.crc32(input, initial) == expected diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py --- a/pypy/module/zlib/interp_zlib.py +++ b/pypy/module/zlib/interp_zlib.py @@ -20,25 +20,15 @@ return intmask((x ^ SIGN_EXTEND2) - SIGN_EXTEND2) -@unwrap_spec(string='bufferstr') -def crc32(space, string, w_start = rzlib.CRC32_DEFAULT_START): +@unwrap_spec(string='bufferstr', start='truncatedint') +def crc32(space, string, start = rzlib.CRC32_DEFAULT_START): """ crc32(string[, start]) -- Compute a CRC-32 checksum of string. An optional starting value can be specified. The returned checksum is an integer. """ - if space.is_true(space.isinstance(w_start, space.w_long)): - num = space.bigint_w(w_start) - ustart = num.uintmask() - elif space.is_true(space.isinstance(w_start, space.w_int)): - start = space.int_w(w_start) ustart = r_uint(start) - else: - raise OperationError(space.w_TypeError, - space.wrap("crc32() argument 2 must " - "be integer<k>, not str")) - checksum = rzlib.crc32(string, ustart) # This is, perhaps, a little stupid. zlib returns the checksum unsigned. @@ -51,7 +41,7 @@ return space.wrap(checksum) -@unwrap_spec(string='bufferstr', start=r_uint) +@unwrap_spec(string='bufferstr', start='truncatedint') def adler32(space, string, start=rzlib.ADLER32_DEFAULT_START): """ adler32(string[, start]) -- Compute an Adler-32 checksum of string. @@ -59,7 +49,8 @@ An optional starting value can be specified. The returned checksum is an integer. """ - checksum = rzlib.adler32(string, start) + ustart = r_uint(start) + checksum = rzlib.adler32(string, ustart) # See comments in crc32() for the following line checksum = unsigned_to_signed_32bit(checksum) diff --git a/pypy/module/zlib/test/test_zlib.py b/pypy/module/zlib/test/test_zlib.py --- a/pypy/module/zlib/test/test_zlib.py +++ b/pypy/module/zlib/test/test_zlib.py @@ -78,15 +78,17 @@ def test_crc32_negative_long_start(self): v = self.zlib.crc32('', -1L) assert v == -1 + assert self.zlib.crc32('foo', -99999999999999999999999) == 1611238463 def test_crc32_long_start(self): import sys v = self.zlib.crc32('', sys.maxint*2) assert v == -2 + assert self.zlib.crc32('foo', 99999999999999999999999) == 1635107045 def test_adler32(self): """ - When called with a string, zlib.crc32 should compute its adler 32 + When called with a string, zlib.adler32() should compute its adler 32 checksum and return it as a signed 32 bit integer. On 64-bit machines too (it is a bug in CPython < 2.6 to return unsigned values in this case). @@ -113,6 +115,9 @@ helloworldsum = self.zlib.adler32(world, hellosum) assert helloworldsum == self.zlib.adler32(hello + world) + assert self.zlib.adler32('foo', -1) == 45547858 + assert self.zlib.adler32('foo', 99999999999999999999999) == -114818734 + def test_invalidLevel(self): """ _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit