[pypy-commit] pypy default: Fix PyLong_FromVoidPtr to return int/long like CPython.

arigo pypy.commits at gmail.com
Sun Sep 18 13:11:48 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r87204:8bbafbedd0b2
Date: 2016-09-18 19:11 +0200
http://bitbucket.org/pypy/pypy/changeset/8bbafbedd0b2/

Log:	Fix PyLong_FromVoidPtr to return int/long like CPython. Hopefully
	fix a translation failure on 32-bit too.

diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -6,7 +6,6 @@
 from pypy.interpreter.error import OperationError
 from pypy.module.cpyext.intobject import PyInt_AsUnsignedLongMask
 from rpython.rlib.rbigint import rbigint
-from rpython.rlib.rarithmetic import widen
 
 
 PyLong_Check, PyLong_CheckExact = build_type_checkers("Long")
@@ -28,25 +27,25 @@
     """Return a new PyLongObject object from a C size_t, or NULL on
     failure.
     """
-    return space.wrap(val)
+    return space.newlong_from_rarith_int(val)
 
 @cpython_api([rffi.LONGLONG], PyObject)
 def PyLong_FromLongLong(space, val):
     """Return a new PyLongObject object from a C long long, or NULL
     on failure."""
-    return space.newlong(val)
+    return space.newlong_from_rarith_int(val)
 
 @cpython_api([rffi.ULONG], PyObject)
 def PyLong_FromUnsignedLong(space, val):
     """Return a new PyLongObject object from a C unsigned long, or
     NULL on failure."""
-    return space.wrap(val)
+    return space.newlong_from_rarith_int(val)
 
 @cpython_api([rffi.ULONGLONG], PyObject)
 def PyLong_FromUnsignedLongLong(space, val):
     """Return a new PyLongObject object from a C unsigned long long,
     or NULL on failure."""
-    return space.wrap(val)
+    return space.newlong_from_rarith_int(val)
 
 @cpython_api([PyObject], rffi.ULONG, error=-1)
 def PyLong_AsUnsignedLong(space, w_long):
@@ -203,7 +202,10 @@
     can be retrieved from the resulting value using PyLong_AsVoidPtr().
 
     If the integer is larger than LONG_MAX, a positive long integer is returned."""
-    return space.newlong(rffi.cast(ADDR, p))
+    value = rffi.cast(ADDR, p)    # signed integer
+    if value < 0:
+        return space.newlong_from_rarith_int(rffi.cast(lltype.Unsigned, p))
+    return space.wrap(value)
 
 @cpython_api([PyObject], rffi.VOIDP, error=lltype.nullptr(rffi.VOIDP.TO))
 def PyLong_AsVoidPtr(space, w_long):
diff --git a/pypy/module/cpyext/test/test_longobject.py b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -1,5 +1,6 @@
 import sys, py
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.rarithmetic import maxint
 from pypy.objspace.std.intobject import W_IntObject
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.module.cpyext.test.test_api import BaseApiTest
@@ -108,10 +109,26 @@
         lltype.free(overflow, flavor='raw')
 
     def test_as_voidptr(self, space, api):
+        # CPython returns an int (not a long) depending on the value
+        # passed to PyLong_FromVoidPtr().  In all cases, NULL becomes
+        # the int 0.
         w_l = api.PyLong_FromVoidPtr(lltype.nullptr(rffi.VOIDP.TO))
-        assert isinstance(w_l, W_LongObject)
-        assert space.unwrap(w_l) == 0L
+        assert space.is_w(space.type(w_l), space.w_int)
+        assert space.unwrap(w_l) == 0
         assert api.PyLong_AsVoidPtr(w_l) == lltype.nullptr(rffi.VOIDP.TO)
+        # Positive values also return an int (assuming, like always in
+        # PyPy, that an int is big enough to store any pointer).
+        p = rffi.cast(rffi.VOIDP, maxint)
+        w_l = api.PyLong_FromVoidPtr(p)
+        assert space.is_w(space.type(w_l), space.w_int)
+        assert space.unwrap(w_l) == maxint
+        assert api.PyLong_AsVoidPtr(w_l) == p
+        # Negative values always return a long.
+        p = rffi.cast(rffi.VOIDP, -maxint-1)
+        w_l = api.PyLong_FromVoidPtr(p)
+        assert space.is_w(space.type(w_l), space.w_long)
+        assert space.unwrap(w_l) == maxint+1
+        assert api.PyLong_AsVoidPtr(w_l) == p
 
     def test_sign_and_bits(self, space, api):
         if space.is_true(space.lt(space.sys.get('version_info'),
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -270,6 +270,9 @@
             return W_SmallLongObject.fromint(val)
         return W_LongObject.fromint(self, val)
 
+    def newlong_from_rarith_int(self, val): # val is an rarithmetic type 
+        return W_LongObject.fromrarith_int(val)
+
     def newlong_from_rbigint(self, val):
         return newlong(self, val)
 
diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -25,7 +25,6 @@
         space.raises_w(space.w_OverflowError, space.float_w, w_big)
 
     def test_rint_variants(self):
-        py.test.skip("XXX broken!")
         from rpython.rtyper.tool.rfficache import platform
         space = self.space
         for r in platform.numbertype_to_rclass.values():
@@ -36,8 +35,8 @@
             for x in values:
                 if not r.SIGNED:
                     x &= r.MASK
-                w_obj = space.wrap(r(x))
-                assert space.bigint_w(w_obj).eq(rbigint.fromint(x))
+                w_obj = space.newlong_from_rarith_int(r(x))
+                assert space.bigint_w(w_obj).eq(rbigint.fromlong(x))
 
 
 class AppTestLong:


More information about the pypy-commit mailing list