packages feed

guarded-allocation 0.0 → 0.0.1

raw patch · 5 files changed

+211/−13 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Foreign.Marshal.Array.Guarded: data MutablePtr a
+ Foreign.Marshal.Array.Guarded: freeze :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded: freezeInplace :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded: new :: Storable a => Int -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded: thaw :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded: thawInplace :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded: withMutablePtr :: MutablePtr a -> (Ptr a -> IO b) -> IO b
+ Foreign.Marshal.Array.Guarded.Debug: data MutablePtr a
+ Foreign.Marshal.Array.Guarded.Debug: freeze :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded.Debug: freezeInplace :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded.Debug: new :: Storable a => Int -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Debug: thaw :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Debug: thawInplace :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Debug: withMutablePtr :: MutablePtr a -> (Ptr a -> IO b) -> IO b
+ Foreign.Marshal.Array.Guarded.Plain: data MutablePtr a
+ Foreign.Marshal.Array.Guarded.Plain: freeze :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded.Plain: freezeInplace :: Storable a => Int -> MutablePtr a -> IO (ForeignPtr a)
+ Foreign.Marshal.Array.Guarded.Plain: new :: Storable a => Int -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Plain: thaw :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Plain: thawInplace :: Storable a => Int -> ForeignPtr a -> IO (MutablePtr a)
+ Foreign.Marshal.Array.Guarded.Plain: withMutablePtr :: MutablePtr a -> (Ptr a -> IO b) -> IO b
- Foreign.Marshal.Array.Guarded: alloca :: (Storable a) => Int -> (Ptr a -> IO b) -> IO b
+ Foreign.Marshal.Array.Guarded: alloca :: Storable a => Int -> (Ptr a -> IO b) -> IO b
- Foreign.Marshal.Array.Guarded: create :: (Storable a) => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)
+ Foreign.Marshal.Array.Guarded: create :: Storable a => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)
- Foreign.Marshal.Array.Guarded.Debug: alloca :: (Storable a) => Int -> (Ptr a -> IO b) -> IO b
+ Foreign.Marshal.Array.Guarded.Debug: alloca :: Storable a => Int -> (Ptr a -> IO b) -> IO b
- Foreign.Marshal.Array.Guarded.Debug: create :: (Storable a) => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)
+ Foreign.Marshal.Array.Guarded.Debug: create :: Storable a => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)
- Foreign.Marshal.Array.Guarded.Plain: alloca :: (Storable a) => Int -> (Ptr a -> IO b) -> IO b
+ Foreign.Marshal.Array.Guarded.Plain: alloca :: Storable a => Int -> (Ptr a -> IO b) -> IO b
- Foreign.Marshal.Array.Guarded.Plain: create :: (Storable a) => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)
+ Foreign.Marshal.Array.Guarded.Plain: create :: Storable a => Int -> (Ptr a -> IO b) -> IO (ForeignPtr a, b)

Files

frontend/debug/Foreign/Marshal/Array/Guarded.hs view
@@ -1,6 +1,15 @@ module Foreign.Marshal.Array.Guarded (+   -- * immutable arrays    Array.create,    Array.alloca,+   -- * mutable arrays+   Array.MutablePtr,+   Array.new,+   Array.withMutablePtr,+   Array.freeze,+   Array.freezeInplace,+   Array.thaw,+   Array.thawInplace,    ) where  import qualified Foreign.Marshal.Array.Guarded.Debug as Array
frontend/plain/Foreign/Marshal/Array/Guarded.hs view
@@ -1,6 +1,15 @@ module Foreign.Marshal.Array.Guarded (+   -- * immutable arrays    Array.create,    Array.alloca,+   -- * mutable arrays+   Array.MutablePtr,+   Array.new,+   Array.withMutablePtr,+   Array.freeze,+   Array.freezeInplace,+   Array.thaw,+   Array.thawInplace,    ) where  import qualified Foreign.Marshal.Array.Guarded.Plain as Array
guarded-allocation.cabal view
@@ -1,5 +1,5 @@ Name:             guarded-allocation-Version:          0.0+Version:          0.0.1 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -38,7 +38,7 @@   README.md  Source-Repository this-  Tag:         0.1+  Tag:         0.0.1   Type:        darcs   Location:    http://hub.darcs.net/thielema/guarded-allocation/ 
src/Foreign/Marshal/Array/Guarded/Debug.hs view
@@ -1,6 +1,15 @@ module Foreign.Marshal.Array.Guarded.Debug (+   -- * immutable arrays    create,    alloca,+   -- * mutable arrays+   MutablePtr,+   new,+   withMutablePtr,+   thaw,+   thawInplace,+   freeze,+   freezeInplace,    ) where  import qualified Foreign.Marshal.Array.Guarded.Plain as Plain@@ -9,16 +18,20 @@          (mallocArray, allocaArray, pokeArray, copyArray, advancePtr) import Foreign.Marshal.Alloc (free) import Foreign.Storable (Storable, peekByteOff, sizeOf)-import Foreign.Concurrent (newForeignPtr)-import Foreign.ForeignPtr (ForeignPtr)+import Foreign.Concurrent (newForeignPtr, addForeignPtrFinalizer)+import Foreign.ForeignPtr (ForeignPtr, withForeignPtr) import Foreign.Ptr (Ptr, castPtr)  import Control.Monad (when)+import Control.Applicative ((<$>)) +import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Data.Foldable (for_) import Data.Word (Word8) +import Text.Printf (printf) + {- | Array creation with additional immutability check, electrical fence and pollution of uncleaned memory.@@ -33,14 +46,9 @@    ptrsA@(_ptrApre, ptrA, _ptrApost) <- fillAll border size ptrApre    result <- f ptrA    checkAll border ptrsA-   ptrB <- mallocArray size-   copyArray ptrB ptrA size+   ptrB <- copyToNew size ptrA    fmap (flip (,) result) $ newForeignPtr ptrA $ do-      for_ (take (arraySize ptrA size) [0..]) $ \i -> do-         a <- peekByteOff ptrA i-         b <- peekByteOff ptrB i-         when (a/=(b::Word8)) $-            error $ "immutable array was altered at byte position " ++ show i+      verify size ptrA ptrB       trash fullSize ptrApre       free ptrApre       free ptrB@@ -58,12 +66,119 @@       return result  ++data MutablePtr a =+   MutablePtr {+      _mutableSize :: !Int,+      _mutableFPtr :: !(ForeignPtr a),+      _mutableFrozenRef :: !(IORef Bool)+   }++new :: (Storable a) => Int -> IO (MutablePtr a)+new size = do+   let border = 64+   let fullSize = size + 2*border+   ptrApre <- mallocArray fullSize+   ptrsA <- fillAll border size ptrApre+   newMutablePtr size =<< newCheckedForeignPtr border fullSize ptrsA+++withMutablePtr :: MutablePtr a -> (Ptr a -> IO b) -> IO b+withMutablePtr (MutablePtr _size fptr frozenRef) f = do+   checkFrozen "withMutablePtr" frozenRef+   withForeignPtr fptr f++thaw :: (Storable a) => Int -> ForeignPtr a -> IO (MutablePtr a)+thaw size fptrB = do+   let border = 64+   let fullSize = size + 2*border+   ptrApre <- mallocArray fullSize+   ptrsA@(_ptrApre, ptrA, _ptrApost) <- fillBorder border size ptrApre+   withForeignPtr fptrB $ \ptrB -> copyArray ptrA ptrB size+   newMutablePtr size =<< newCheckedForeignPtr border fullSize ptrsA++newCheckedForeignPtr ::+   (Storable a) => Int -> Int -> (Ptr a, Ptr a, Ptr a) -> IO (ForeignPtr a)+newCheckedForeignPtr border fullSize ptrsA@(ptrApre, ptrA, _ptrApost) =+   newForeignPtr ptrA $ do+      checkAll border ptrsA+      trash fullSize ptrApre+      free ptrApre++{- |+There is not much we can debug here.+We cannot add a fence since we do not copy the immutable array.+We could debug more+if we would implement 'thawInplace' as a redirection to 'thaw'.+-}+thawInplace :: (Storable a) => Int -> ForeignPtr a -> IO (MutablePtr a)+thawInplace = newMutablePtr++{- |+The 'size' parameter must match the size passed to 'new'.+This is checked.+-}+freeze :: (Storable a) => Int -> MutablePtr a -> IO (ForeignPtr a)+freeze freezeSize (MutablePtr size fptr frozenRef) = do+   checkSize freezeSize size+   checkFrozen "freeze" frozenRef+   ptrA <- withForeignPtr fptr $ copyToNew size+   ptrB <- withForeignPtr fptr $ copyToNew size+   newForeignPtr ptrA $ do+      verify size ptrA ptrB+      trash size ptrA+      free ptrA+      free ptrB++{- |+'freezeInplace' must be the last operation on the 'MutablePtr'+and its associated array.+The 'size' parameter must match the size passed to 'new'.+This is checked.++It may fail if the 'MutablePtr' was constructed using 'thawInplace'+from a 'ForeignPtr' with a C finalizer.+-}+freezeInplace :: (Storable a) => Int -> MutablePtr a -> IO (ForeignPtr a)+freezeInplace freezeSize (MutablePtr size fptr frozenRef) = do+   checkSize freezeSize size+   checkFrozen "freezeInplace" frozenRef+   writeIORef frozenRef True++   withForeignPtr fptr $ \ptrA -> do+      ptrB <- copyToNew size ptrA+      addForeignPtrFinalizer fptr $ do+         verify size ptrA ptrB+         free ptrB+   return fptr+++newMutablePtr :: Int -> ForeignPtr a -> IO (MutablePtr a)+newMutablePtr size fptr = MutablePtr size fptr <$> newIORef False++checkSize :: Int -> Int -> IO ()+checkSize freezeSize size =+   when (freezeSize/=size) $ error $+      printf "allocation (%d) and freeze (%d) size differ" size freezeSize++checkFrozen :: String -> IORef Bool -> IO ()+checkFrozen name frozenRef =+   flip when (error $ name ++ ": array already frozen")+      =<< readIORef frozenRef+++ fillAll :: (Storable a) => Int -> Int -> Ptr a -> IO (Ptr a, Ptr a, Ptr a) fillAll border size ptrPre = do+   ptrs@(_ptrPre, ptr, _ptrPost) <- fillBorder border size ptrPre+   fill ptr size [0xDE,0xAD,0xF0,0x0D]+   return ptrs++fillBorder :: (Storable a) => Int -> Int -> Ptr a -> IO (Ptr a, Ptr a, Ptr a)+fillBorder border size ptrPre = do    let ptr = advancePtr ptrPre border    let ptrPost = advancePtr ptr size    fill ptrPre border [0xAB,0xAD,0xCA,0xFE]-   fill ptr size [0xDE,0xAD,0xF0,0x0D]    fill ptrPost border [0xAB,0xAD,0xCA,0xFE]    return (ptrPre, ptr, ptrPost) @@ -88,6 +203,20 @@       a <- peekByteOff ptr i       when (a/=(b::Word8)) $          error $ "damaged " ++ name ++ " fence at position " ++ show i++copyToNew :: (Storable a) => Int -> Ptr a -> IO (Ptr a)+copyToNew size ptrA = do+   ptrB <- mallocArray size+   copyArray ptrB ptrA size+   return ptrB++verify :: (Storable a) => Int -> Ptr a -> Ptr a -> IO ()+verify size ptrA ptrB =+   for_ (take (arraySize ptrA size) [0..]) $ \i -> do+      a <- peekByteOff ptrA i+      b <- peekByteOff ptrB i+      when (a/=(b::Word8)) $+         error $ "immutable array was altered at byte position " ++ show i  arraySize :: (Storable a) => Ptr a -> Int -> Int arraySize ptr n = arraySizeAux ptr n $ error "arraySize: undefined element"
src/Foreign/Marshal/Array/Guarded/Plain.hs view
@@ -1,9 +1,18 @@ module Foreign.Marshal.Array.Guarded.Plain (+   -- * immutable arrays    create,    alloca,+   -- * mutable arrays+   MutablePtr,+   new,+   withMutablePtr,+   freeze,+   freezeInplace,+   thaw,+   thawInplace,    ) where -import Foreign.Marshal.Array (allocaArray)+import Foreign.Marshal.Array (allocaArray, copyArray) import Foreign.Storable (Storable) import Foreign.ForeignPtr (ForeignPtr, withForeignPtr, mallocForeignPtrArray) import Foreign.Ptr (Ptr)@@ -18,3 +27,45 @@  alloca :: (Storable a) => Int -> (Ptr a -> IO b) -> IO b alloca = allocaArray+++newtype MutablePtr a = MutablePtr (ForeignPtr a)++new :: (Storable a) => Int -> IO (MutablePtr a)+new size = MutablePtr <$> mallocForeignPtrArray size++withMutablePtr :: MutablePtr a -> (Ptr a -> IO b) -> IO b+withMutablePtr (MutablePtr fptr) = withForeignPtr fptr++{- |+The 'size' parameter must match the size passed to 'new'.+This is not checked.+-}+freeze :: (Storable a) => Int -> MutablePtr a -> IO (ForeignPtr a)+freeze size (MutablePtr src) = copyToNew size src++{- |+'freezeInplace' must be the last operation on the 'MutablePtr'+and its associated array.+This is not checked.+-}+{-# INLINE freezeInplace #-}+freezeInplace :: (Storable a) => Int -> MutablePtr a -> IO (ForeignPtr a)+freezeInplace _ (MutablePtr fptr) = return fptr+++thaw :: (Storable a) => Int -> ForeignPtr a -> IO (MutablePtr a)+thaw size src = MutablePtr <$> copyToNew size src++{-# INLINE thawInplace #-}+thawInplace :: (Storable a) => Int -> ForeignPtr a -> IO (MutablePtr a)+thawInplace _size fptr = return $ MutablePtr fptr+++copyToNew :: (Storable a) => Int -> ForeignPtr a -> IO (ForeignPtr a)+copyToNew size src = do+   dst <- mallocForeignPtrArray size+   withForeignPtr dst $ \dstPtr ->+      withForeignPtr src $ \srcPtr ->+      copyArray dstPtr srcPtr size+   return dst