From 990163c444d36b5a9471f9d2b657e1fa793d5b26 Mon Sep 17 00:00:00 2001 From: James Clarke Date: Mon, 6 Nov 2017 11:44:39 +0000 Subject: [PATCH] Don't perform unaligned writes when forbidden Some architectures, such as SPARC, trap on unaligned memory accesses, and poke makes no guarantees about its behaviour if the address is not sufficiently aligned. Therefore we should use a temporary buffer if asked to write to an unaligned address, unless we know for sure the architecture supports it without trapping. --- Changelog.md | 1 + Data/ByteString/Builder/Prim/Binary.hs | 3 --- Data/ByteString/Builder/Prim/Internal.hs | 12 ++++++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index cd04ad562..2aa5cad16 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ 0.10.10.0 TBD * Add conversions between ShortByteString and CString (#126) + * Don't perform unaligned writes when it isn't known to be safe (#133) 0.10.8.2 Duncan Coutts Feb 2017 diff --git a/Data/ByteString/Builder/Prim/Binary.hs b/Data/ByteString/Builder/Prim/Binary.hs index af0c0bb5d..bd7e40d91 100644 --- a/Data/ByteString/Builder/Prim/Binary.hs +++ b/Data/ByteString/Builder/Prim/Binary.hs @@ -272,9 +272,6 @@ int64LE :: FixedPrim Int64 int64LE = fromIntegral >$< word64LE --- TODO: Ensure that they are safe on architectures where an unaligned write is --- an error. - -- | Encode a single native machine 'Int'. The 'Int's is encoded in host order, -- host endian form, for the machine you are on. On a 64 bit machine the 'Int' -- is an 8 byte value, on a 32 bit machine, 4 bytes. Values encoded this way diff --git a/Data/ByteString/Builder/Prim/Internal.hs b/Data/ByteString/Builder/Prim/Internal.hs index fb52404f2..1f1c09377 100644 --- a/Data/ByteString/Builder/Prim/Internal.hs +++ b/Data/ByteString/Builder/Prim/Internal.hs @@ -198,7 +198,19 @@ liftFixedToBounded = toB {-# INLINE CONLIKE storableToF #-} storableToF :: forall a. Storable a => FixedPrim a +-- Not all architectures are forgiving of unaligned accesses; whitelist ones +-- which are known not to trap (either to the kernel for emulation, or crash). +#if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH) \ + || ((defined(arm_HOST_ARCH) || defined(aarch64_HOST_ARCH)) \ + && defined(__ARM_FEATURE_UNALIGNED)) \ + || defined(powerpc_HOST_ARCH) || defined(powerpc64_HOST_ARCH) \ + || defined(powerpc64le_HOST_ARCH) storableToF = FP (sizeOf (undefined :: a)) (\x op -> poke (castPtr op) x) +#else +storableToF = FP (sizeOf (undefined :: a)) $ \x op -> + if (ptrToWordPtr op) `mod` (fromIntegral (alignment (undefined :: a))) == 0 then poke (castPtr op) x + else with x $ \tp -> copyBytes op (castPtr tp) (sizeOf (undefined :: a)) +#endif {- {-# INLINE CONLIKE liftIOF #-}