Author: David Schneider <[email protected]>
Branch:
Changeset: r64957:162603593f00
Date: 2013-06-23 04:24 -0500
http://bitbucket.org/pypy/pypy/changeset/162603593f00/
Log: ctypes/_rawffi can generate unaligned access to floating point
fields in structures. Directly reading unaligned floats from memory
is not supported on ARM. This change adds a wrapper around the reads
and writes that checks the pointer alignment and uses memcpy in case
of unaligned access on ARM.
diff --git a/pypy/module/_rawffi/array.py b/pypy/module/_rawffi/array.py
--- a/pypy/module/_rawffi/array.py
+++ b/pypy/module/_rawffi/array.py
@@ -13,19 +13,9 @@
from pypy.module._rawffi.interp_rawffi import TYPEMAP
from pypy.module._rawffi.interp_rawffi import size_alignment
from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
+from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr
from rpython.rlib.rarithmetic import r_uint
-def push_elem(ll_array, pos, value):
- TP = lltype.typeOf(value)
- ll_array = rffi.cast(rffi.CArrayPtr(TP), ll_array)
- ll_array[pos] = value
-push_elem._annspecialcase_ = 'specialize:argtype(2)'
-
-def get_elem(ll_array, pos, ll_t):
- ll_array = rffi.cast(rffi.CArrayPtr(ll_t), ll_array)
- return ll_array[pos]
-get_elem._annspecialcase_ = 'specialize:arg(2)'
-
class W_Array(W_DataShape):
def __init__(self, basicffitype, size):
@@ -57,7 +47,7 @@
" array length"))
for num in range(iterlength):
w_item = items_w[num]
- unwrap_value(space, push_elem, result.ll_buffer, num,
+ unwrap_value(space, write_ptr, result.ll_buffer, num,
self.itemcode, w_item)
return space.wrap(result)
@@ -118,7 +108,7 @@
raise segfault_exception(space, "setting element of freed array")
if num >= self.length or num < 0:
raise OperationError(space.w_IndexError, space.w_None)
- unwrap_value(space, push_elem, self.ll_buffer, num,
+ unwrap_value(space, write_ptr, self.ll_buffer, num,
self.shape.itemcode, w_value)
def descr_setitem(self, space, w_index, w_value):
@@ -136,7 +126,7 @@
raise segfault_exception(space, "accessing elements of freed
array")
if num >= self.length or num < 0:
raise OperationError(space.w_IndexError, space.w_None)
- return wrap_value(space, get_elem, self.ll_buffer, num,
+ return wrap_value(space, read_ptr, self.ll_buffer, num,
self.shape.itemcode)
def descr_getitem(self, space, w_index):
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
@@ -2,7 +2,7 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from rpython.rtyper.lltypesystem import lltype, rffi
-from pypy.module._rawffi.array import push_elem
+from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr
from pypy.module._rawffi.structure import W_Structure
from pypy.module._rawffi.interp_rawffi import (W_DataInstance, letter2tp,
unwrap_value, unpack_argshapes, got_libffi_error)
@@ -40,7 +40,7 @@
args_w[i] = space.wrap(rffi.cast(rffi.ULONG, ll_args[i]))
w_res = space.call(w_callable, space.newtuple(args_w))
if callback_ptr.result is not None: # don't return void
- unwrap_value(space, push_elem, ll_res, 0,
+ unwrap_value(space, write_ptr, ll_res, 0,
callback_ptr.result, w_res)
except OperationError, e:
tbprint(space, space.wrap(e.get_traceback()),
diff --git a/pypy/module/_rawffi/interp_rawffi.py
b/pypy/module/_rawffi/interp_rawffi.py
--- a/pypy/module/_rawffi/interp_rawffi.py
+++ b/pypy/module/_rawffi/interp_rawffi.py
@@ -5,6 +5,7 @@
from rpython.rlib.clibffi import *
from rpython.rtyper.lltypesystem import lltype, rffi
+from rpython.rtyper.tool import rffi_platform
from rpython.rlib.unroll import unrolling_iterable
import rpython.rlib.rposix as rposix
@@ -43,6 +44,8 @@
}
TYPEMAP_PTR_LETTERS = "POszZ"
TYPEMAP_NUMBER_LETTERS = "bBhHiIlLqQ?"
+TYPEMAP_FLOAT_LETTERS = "fd" # XXX long doubles are not propperly supported in
+ # rpython, so we ignore then here
if _MS_WINDOWS:
TYPEMAP['X'] = ffi_type_pointer
@@ -239,6 +242,52 @@
)
unroll_letters_for_numbers = unrolling_iterable(TYPEMAP_NUMBER_LETTERS)
+unroll_letters_for_floats = unrolling_iterable(TYPEMAP_FLOAT_LETTERS)
+
+_ARM = rffi_platform.getdefined('__arm__', '')
+
+def read_ptr(ptr, ofs, TP):
+ T = lltype.Ptr(rffi.CArray(TP))
+ for c in unroll_letters_for_floats:
+ # Note: if we are on ARM and have a float-ish value that is not word
+ # aligned accessing it directly causes a SIGBUS. Instead we use memcpy
+ # to avoid the problem
+ if (_ARM and LL_TYPEMAP[c] is TP
+ and rffi.cast(lltype.Signed, ptr) & 3 != 0):
+ if ofs != 0:
+ ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP))
+ with lltype.scoped_alloc(T.TO, 1) as t_array:
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, t_array),
+ rffi.cast(rffi.VOIDP, ptr),
+ rffi.sizeof(TP))
+ ptr_val = t_array[0]
+ return ptr_val
+ else:
+ return rffi.cast(T, ptr)[ofs]
+read_ptr._annspecialcase_ = 'specialize:arg(2)'
+
+def write_ptr(ptr, ofs, value):
+ TP = lltype.typeOf(value)
+ T = lltype.Ptr(rffi.CArray(TP))
+ for c in unroll_letters_for_floats:
+ # Note: if we are on ARM and have a float-ish value that is not word
+ # aligned accessing it directly causes a SIGBUS. Instead we use memcpy
+ # to avoid the problem
+ if (_ARM and LL_TYPEMAP[c] is TP
+ and rffi.cast(lltype.Signed, ptr) & 3 != 0):
+ if ofs != 0:
+ ptr = rffi.ptradd(ptr, ofs*rffi.sizeof(TP))
+ with lltype.scoped_alloc(T.TO, 1) as s_array:
+ s_array[0] = value
+ rffi.c_memcpy(
+ rffi.cast(rffi.VOIDP, ptr),
+ rffi.cast(rffi.VOIDP, s_array),
+ rffi.sizeof(TP))
+ return
+ else:
+ rffi.cast(T, ptr)[ofs] = value
+write_ptr._annspecialcase_ = 'specialize:argtype(2)'
def segfault_exception(space, reason):
w_mod = space.getbuiltinmodule("_rawffi")
diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py
--- a/pypy/module/_rawffi/structure.py
+++ b/pypy/module/_rawffi/structure.py
@@ -12,8 +12,10 @@
from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance
from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
-from pypy.module._rawffi.interp_rawffi import size_alignment, LL_TYPEMAP
+from pypy.module._rawffi.interp_rawffi import LL_TYPEMAP
from pypy.module._rawffi.interp_rawffi import unroll_letters_for_numbers
+from pypy.module._rawffi.interp_rawffi import size_alignment
+from pypy.module._rawffi.interp_rawffi import read_ptr, write_ptr
from rpython.rlib import clibffi
from rpython.rlib.rarithmetic import intmask, signedtype, widen
from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong
@@ -289,19 +291,18 @@
value = widen(value)
bitmask = BIT_MASK(numbits, TP)
#
- current = widen(rffi.cast(T, ptr)[0])
+ current = widen(read_ptr(ptr, 0, TP))
current &= ~ (bitmask << lowbit)
current |= (value & bitmask) << lowbit
value = rffi.cast(TP, current)
break
-
- rffi.cast(T, ptr)[0] = value
+ write_ptr(ptr, 0, value)
push_field._annspecialcase_ = 'specialize:argtype(2)'
def cast_pos(self, i, ll_t):
pos = rffi.ptradd(self.ll_buffer, self.shape.ll_positions[i])
TP = lltype.Ptr(rffi.CArray(ll_t))
- value = rffi.cast(TP, pos)[0]
+ value = read_ptr(pos, 0, ll_t)
# Handle bitfields
for c in unroll_letters_for_numbers:
diff --git a/pypy/module/_rawffi/test/test__rawffi.py
b/pypy/module/_rawffi/test/test__rawffi.py
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -211,6 +211,7 @@
cls.w_platform = space.wrap(platform.name)
cls.w_sizes_and_alignments = space.wrap(dict(
[(k, (v.c_size, v.c_alignment)) for k,v in TYPEMAP.iteritems()]))
+ cls.w_typemap = space.wrap(TYPEMAP.keys())
def test_libload(self):
import _rawffi
@@ -751,6 +752,18 @@
assert _rawffi.sizeof(k) == s
assert _rawffi.alignment(k) == a
+ def test_unaligned(self):
+ import _rawffi
+ for k in self.typemap:
+ if k not in 'fdg':
+ continue
+ S = _rawffi.Structure([('pad', 'c'), ('value', k)], pack=1)
+ s = S()
+ s.value = 4
+ assert s.value == 4
+ s.free()
+
+
def test_array_addressof(self):
import _rawffi
lib = _rawffi.CDLL(self.lib_name)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit