Commits

wlav committed d57f7dd

NULL and 0 passing through typed pointers

  • Participants
  • Parent commits f42fb7b
  • Branches reflex-support

Comments (0)

Files changed (5)

File pypy/module/cppyy/converter.py

         return rawobject
     return capi.C_NULL_OBJECT
 
+def get_rawbuffer(space, w_obj):
+    try:
+        buf = space.buffer_w(w_obj)
+        return rffi.cast(rffi.VOIDP, buf.get_raw_address())
+    except Exception:
+        pass
+    # special case: allow integer 0 as NULL
+    try:
+        buf = space.int_w(w_obj)
+        if buf == 0:
+            return rffi.cast(rffi.VOIDP, 0)
+    except Exception:
+        pass
+    # special case: allow None as NULL
+    if space.is_true(space.is_(w_obj, space.w_None)):
+        return rffi.cast(rffi.VOIDP, 0)
+    raise TypeError("not an addressable buffer")
+
 
 class TypeConverter(object):
     _immutable_ = True
 
     def convert_argument(self, space, w_obj, address, call_local):
         w_tc = space.findattr(w_obj, space.wrap('typecode'))
-        if w_tc is None:
-            raise OperationError(space.w_TypeError, space.wrap("can not determine buffer type"))
-        if space.str_w(w_tc) != self.typecode:
+        if w_tc is not None and space.str_w(w_tc) != self.typecode:
             msg = "expected %s pointer type, but received %s" % (self.typecode, space.str_w(w_tc))
             raise OperationError(space.w_TypeError, space.wrap(msg))
         x = rffi.cast(rffi.LONGP, address)
-        buf = space.buffer_w(w_obj)
         try:
-            x[0] = rffi.cast(rffi.LONG, buf.get_raw_address())
-        except ValueError:
+            x[0] = rffi.cast(rffi.LONG, get_rawbuffer(space, w_obj))
+        except TypeError:
             raise OperationError(space.w_TypeError,
                                  space.wrap("raw buffer interface not supported"))
         ba = rffi.cast(rffi.CCHARP, address)
         x = rffi.cast(rffi.VOIDPP, address)
         ba = rffi.cast(rffi.CCHARP, address)
         try:
-            buf = space.buffer_w(w_obj)
-            x[0] = rffi.cast(rffi.VOIDP, buf.get_raw_address())
-        except (OperationError, ValueError), e:
+            x[0] = get_rawbuffer(space, w_obj)
+        except TypeError:
             x[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         ba[capi.c_function_arg_typeoffset()] = 'o'
 
         ba = rffi.cast(rffi.CCHARP, address)
         r = rffi.cast(rffi.VOIDPP, call_local)
         try:
-            buf = space.buffer_w(w_obj)
-            r[0] = rffi.cast(rffi.VOIDP, buf.get_raw_address())
-        except (OperationError, ValueError), e:
+            r[0] = get_rawbuffer(space, w_obj)
+        except TypeError:
             r[0] = rffi.cast(rffi.VOIDP, get_rawobject(space, w_obj))
         x[0] = rffi.cast(rffi.VOIDP, call_local)
         ba[capi.c_function_arg_typeoffset()] = 'a'
         try:
             set_rawobject(space, w_obj, r[0])
         except OperationError:
-            pass             # no set on buffer/array
+            pass             # no set on buffer/array/None
 
 class VoidPtrRefConverter(TypeConverter):
     _immutable_ = True

File pypy/module/cppyy/executor.py

 from pypy.rlib import libffi, clibffi
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
-from pypy.module._rawffi.array import W_Array
+from pypy.module._rawffi.array import W_Array, W_ArrayInstance
 
 from pypy.module.cppyy import helper, capi, ffitypes
 
         lresult = capi.c_call_l(cppmethod, cppthis, num_args, args)
         address = rffi.cast(rffi.ULONG, lresult)
         arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap(self.typecode)))
+        if address == 0:
+            # TODO: fix this hack; fromaddress() will allocate memory if address
+            # is null and there seems to be no way around it (ll_buffer can not
+            # be touched directly)
+            nullarr = arr.fromaddress(space, address, 0)
+            assert isinstance(nullarr, W_ArrayInstance)
+            nullarr.free(space)
+            return nullarr
         return arr.fromaddress(space, address, sys.maxint)
 
 

File pypy/module/cppyy/test/test_advancedcpp.py

         addressofo = array.array('l', [cppyy.addressof(o)])
         assert addressofo.buffer_info()[0] == pp.gime_address_ptr_ptr(addressofo)
 
+        assert 0 == pp.gime_address_ptr(0)
+        assert 0 == pp.gime_address_ptr(None)
+
     def test09_opaque_pointer_assing(self):
         """Test passing around of opaque pointers"""
 

File pypy/module/cppyy/test/test_datatypes.py

 currpath = py.path.local(__file__).dirpath()
 test_dct = str(currpath.join("datatypesDict.so"))
 
-space = gettestobjspace(usemodules=['cppyy', 'array'])
+space = gettestobjspace(usemodules=['cppyy', 'array', '_rawffi'])
 
 def setup_module(mod):
     if sys.platform == 'win32':
             for i in range(self.N):
                 assert ca[i] == b[i]
 
+        # NULL/None passing (will use short*)
+        assert not c.pass_array(0)
+        raises(Exception, c.pass_array(0).__getitem__, 0)    # raises SegfaultException
+        assert not c.pass_array(None)
+        raises(Exception, c.pass_array(None).__getitem__, 0) # id.
+
         c.destruct()
 
     def test05_class_read_access(self):

File pypy/module/cppyy/test/test_zjit.py

     r_longlong_w = int_w
     r_ulonglong_w = uint_w
 
+    def is_(self, w_obj1, w_obj2):
+        return w_obj1 is w_obj2
+
     def isinstance_w(self, w_obj, w_type):
         assert isinstance(w_obj, FakeBase)
         return w_obj.typename == w_type.name
 
+    def is_true(self, w_obj):
+        return not not w_obj
+
     def type(self, w_obj):
         return FakeType("fake")