common/util/Util/ASan.hs (77 lines of code) (raw):

-- Copyright (c) Facebook, Inc. and its affiliates. module Util.ASan ( alloca , allocaBytes , allocaArray , allocaArray0 , allocaBytesAligned , with , byteStringWithCString , byteStringWithCStringLen , textWithCStringLen , textWithCString , textUseAsPtr ) where import Control.Exception import Foreign hiding (alloca, allocaBytes, allocaBytesAligned, allocaArray, allocaArray0, with) import Foreign.C import qualified Data.ByteString as BS import qualified Data.ByteString.Internal as BI import Data.Text.Internal (Text(..)) import Data.Text.Encoding (encodeUtf8) import qualified Data.Text.Foreign as TF -- The following functions already support ASan (they already allocate using -- malloc): -- newCStringFromText alloca :: Storable a => (Ptr a -> IO b) -> IO b alloca = doAlloca undefined where doAlloca :: Storable a' => a' -> (Ptr a' -> IO b') -> IO b' doAlloca dummy = allocaBytesAligned (sizeOf dummy) (alignment dummy) allocaBytes :: Int -> (Ptr a -> IO b) -> IO b allocaBytes size = bracket (mallocBytes size) free -- alignedAlloc calls an aligned allocation function that is platform-dependent -- void *alignedAlloc( size_t alignment, size_t size ); foreign import ccall unsafe "alignedAlloc" cAlignedAlloc :: CSize -> CSize -> IO (Ptr a) allocaBytesAligned :: Int -> Int -> (Ptr a -> IO b) -> IO b allocaBytesAligned size alignment = bracket (cAlignedAlloc (fromIntegral alignment) (fromIntegral size)) free allocaArray :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray = doAlloca undefined where doAlloca :: Storable a' => a' -> Int -> (Ptr a' -> IO b') -> IO b' doAlloca dummy size = allocaBytesAligned (size * sizeOf dummy) (alignment dummy) allocaArray0 :: Storable a => Int -> (Ptr a -> IO b) -> IO b allocaArray0 size = allocaArray (size + 1) with :: Storable a => a -> (Ptr a -> IO b) -> IO b with val f = alloca $ \ptr -> do poke ptr val f ptr -- Text / ByteString marshalling textWithCString :: Text -> (CString -> IO a) -> IO a textWithCString = byteStringWithCString . encodeUtf8 byteStringWithCString :: BS.ByteString -> (CString -> IO a) -> IO a byteStringWithCString (BI.PS fp off len) fun = allocaBytes (len+1) $ \ptr' -> do withForeignPtr fp $ \ptr -> do copyBytes ptr' (ptr `plusPtr` off) len poke (ptr' `plusPtr` len) (0 :: Word8) fun ptr' textWithCStringLen :: Text -> (CStringLen -> IO a) -> IO a textWithCStringLen = byteStringWithCStringLen . encodeUtf8 byteStringWithCStringLen :: BS.ByteString -> (CStringLen -> IO a) -> IO a byteStringWithCStringLen (BI.PS _ _ 0) fun = fun (nullPtr, 0) byteStringWithCStringLen (BI.PS fp off len) fun = allocaBytes len $ \ptr' -> do withForeignPtr fp $ \ptr -> copyBytes ptr' (ptr `plusPtr` off) len fun (ptr', len) -- Text marshalling textUseAsPtr :: Text -> (Ptr Word16 -> TF.I16 -> IO a) -> IO a textUseAsPtr t@(Text _arr _off len) action = allocaBytes (len * 2) $ \buf -> do TF.unsafeCopyToPtr t buf action (castPtr buf) (fromIntegral len)