1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
From 08d19aaf328fd456960f689fa66e0bfb7eebf28b Mon Sep 17 00:00:00 2001
From: Mike Pilgrem <mpilgrem@users.noreply.github.com>
Date: Sun, 20 Oct 2024 20:29:04 +0100
Subject: [PATCH] Fix #1 Enforce that the Word64 values used are little-endian.
Index: b/src/Data/StaticBytes.hs
===================================================================
--- a/src/Data/StaticBytes.hs
+++ b/src/Data/StaticBytes.hs
@@ -34,6 +34,7 @@ import qualified Data.Vector.Unboxed.Bas
import Foreign.ForeignPtr
import Foreign.Ptr
import Foreign.Storable
+import GHC.ByteOrder ( ByteOrder (..), targetByteOrder )
import RIO hiding ( words )
import System.IO.Unsafe ( unsafePerformIO )
@@ -75,20 +76,23 @@ class DynamicBytes dbytes where
lengthD :: dbytes -> Int
-- Yeah, it looks terrible to use a list here, but fusion should kick in
withPeekD :: dbytes -> ((Int -> IO Word64) -> IO a) -> IO a
+ -- ^ This assumes that the Word64 values are all little-endian.
-- | May throw a runtime exception if invariants are violated!
fromWordsD :: Int -> [Word64] -> dbytes
+ -- ^ This assumes that the Word64 values are all little-endian.
fromWordsForeign ::
(ForeignPtr a -> Int -> b)
-> Int
-> [Word64]
+ -- ^ The Word64 values are assumed to be little-endian.
-> b
fromWordsForeign wrapper len words0 = unsafePerformIO $ do
fptr <- B.mallocByteString len
withForeignPtr fptr $ \ptr -> do
let loop _ [] = pure ()
loop off (w:ws) = do
- pokeElemOff (castPtr ptr) off w
+ pokeElemOff (castPtr ptr) off (fromLE64 w)
loop (off + 1) ws
loop 0 words0
pure $ wrapper fptr len
@@ -96,6 +100,7 @@ fromWordsForeign wrapper len words0 = un
withPeekForeign ::
(ForeignPtr a, Int, Int)
-> ((Int -> IO Word64) -> IO b)
+ -- ^ The Word64 values are assumed to be little-endian.
-> IO b
withPeekForeign (fptr, off, len) inner =
withForeignPtr fptr $ \ptr -> do
@@ -109,7 +114,7 @@ withPeekForeign (fptr, off, len) inner =
let w64' = shiftL (fromIntegral w8) (i * 8) .|. w64
loop w64' (i + 1)
loop 0 0
- | otherwise = peekByteOff ptr (off + off')
+ | otherwise = toLE64 <$> peekByteOff ptr (off + off')
inner f
instance DynamicBytes B.ByteString where
@@ -129,7 +134,7 @@ instance word8 ~ Word8 => DynamicBytes (
let loop _ [] =
VP.Vector 0 len <$> BA.unsafeFreezeByteArray ba
loop i (w:ws) = do
- BA.writeByteArray ba i w
+ BA.writeByteArray ba i (fromLE64 w)
loop (i + 1) ws
loop 0 words0
withPeekD (VP.Vector off len ba) inner = do
@@ -143,7 +148,8 @@ instance word8 ~ Word8 => DynamicBytes (
let w64' = shiftL (fromIntegral w8) (i * 8) .|. w64
loop w64' (i + 1)
loop 0 0
- | otherwise = pure $ BA.indexByteArray ba (off + (off' `div` 8))
+ | otherwise = pure $
+ toLE64 $ BA.indexByteArray ba (off + (off' `div` 8))
inner f
instance word8 ~ Word8 => DynamicBytes (VU.Vector word8) where
@@ -244,3 +250,13 @@ fromStatic ::
=> sbytes
-> dbytes
fromStatic = fromWordsD (lengthS (Nothing :: Maybe sbytes)) . ($ []) . toWordsS
+
+-- | Convert a 64 bit value in CPU endianess to little endian.
+toLE64 :: Word64 -> Word64
+toLE64 = case targetByteOrder of
+ BigEndian -> byteSwap64
+ LittleEndian -> id
+
+-- | Convert a little endian 64 bit value to CPU endianess.
+fromLE64 :: Word64 -> Word64
+fromLE64 = toLE64
|