Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a pointer value in Haskell?

I wish to manipulate data on a very low level.

Therefore I have a function that receives a virtual memory address as an integer and "does stuff" with this memory address. I interfaced this function from C, so it has the type (CUInt -> a). The memory I want to link is a Word8 in a file. Sadly, I have no idea how to access the pointer value to that Word8.

To be clear, I do not need the value of the Word8, i need the value to the virtual memory address, which is the value of the pointer to it.

like image 477
ChrisQuignon Avatar asked Mar 05 '10 11:03

ChrisQuignon


2 Answers

For the sake of a simple example, say you want to add an offset to the pointer.

Front matter:

module Main where
import Control.Monad (forM_)
import Data.Char (chr)
import Data.Word (Word8)
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr)
import Foreign.Storable (peek)
import System.IO.MMap (Mode(ReadOnly), mmapFileForeignPtr)

Yes, you wrote that you don't want the value of the Word8, but I've retrieved it with peek to demonstrate that the pointer is valid. You might be tempted to return the Ptr from inside withForeignPtr, but the documentation warns against that:

Note that it is not safe to return the pointer from the action and use it after the action completes. All uses of the pointer should be inside the withForeignPtr bracket. The reason for this unsafeness is the same as for unsafeForeignPtrToPtr below: the finalizer may run earlier than expected, because the compiler can only track usage of the ForeignPtr object, not a Ptr object made from it.

The code is straightforward:

doStuff :: ForeignPtr Word8 -> Int -> IO ()
doStuff fp i =
  withForeignPtr fp $ \p -> do
    let addr = p `plusPtr` i
    val <- peek addr :: IO Word8
    print (addr, val, chr $ fromIntegral val)

To approximate “a Word8 in a File” from your question, the main program memory-maps a file and uses that buffer to do stuff with memory addresses.

main :: IO ()
main = do
  (p,offset,size) <- mmapFileForeignPtr path mode range
  forM_ [0 .. size-1] $ \i -> do
    doStuff p (offset + i)
  where
    path  = "/tmp/input.dat"
    mode  = ReadOnly
    range = Nothing
 -- range = Just (4,3)

Output:

(0x00007f1b40edd000,71,'G')
(0x00007f1b40edd001,117,'u')
(0x00007f1b40edd002,116,'t')
(0x00007f1b40edd003,101,'e')
(0x00007f1b40edd004,110,'n')
(0x00007f1b40edd005,32,' ')
(0x00007f1b40edd006,77,'M')
(0x00007f1b40edd007,111,'o')
(0x00007f1b40edd008,114,'r')
(0x00007f1b40edd009,103,'g')
(0x00007f1b40edd00a,101,'e')
(0x00007f1b40edd00b,110,'n')
(0x00007f1b40edd00c,33,'!')
(0x00007f1b40edd00d,10,'\n')
like image 150
Greg Bacon Avatar answered Oct 06 '22 00:10

Greg Bacon


You are probably looking for ptrToIntPtr and probably fromIntegral to make it a CUInt.

Note that a CUInt cannot represent a pointer on all platforms, though.

like image 22
ben Avatar answered Oct 06 '22 00:10

ben