Allocation & Marshalling Question (again)

Wolfgang Thaller wolfgang.thaller at gmx.net
Thu May 29 11:06:16 EDT 2003


> Whoops, now I see a real problem with what I'm asking for.
>
> I guess since the (hypothetical) withCString is creating
> a new CString (bit like an IORef) it should have type
>
>   withCString :: String -> (CString -> b) -> IO b

It's still highly dangerous. When will the string be freed (no you 
can't rely on the garbage collector, because a CString is a Ptr and not 
a ForeignPtr; so the string has to be freed explicitly).

Assuming your type for withCString...

foreign import ccall foo :: CString -> Word32 -> Word32

main = do
	bar <- (withCString "Hello, world." foo) :: IO (Word32 -> Word32)
	print (bar 42)

OK, what does this do:
The first statement in "main":
	*) Allocates a buffer for the string and pokes the string in there.
	*) Binds the first parameter to foo (i.e., allocates a partial 
application (PAP) on the haskell heap).
	*) Frees the string buffer.	
The print statement:
	*) calls the foreign function "foo" with the pointer to the 
already-freed (!) string buffer and the number 42 as arguments
	*) prints the result

> and I guess my <+ should be..
>   (<+) :: (a -> b) -> ((a -> IO b) -> IO b) -> IO b
>   f <+ alloc = alloc $ \p -> return $ f p
>
> (Well at least that's got rid of the unsafePerformIO :-)
>
> Would this be safe?

It would probably be safer than the version with the unsafePerformIO, 
but still:

foreign import ccall foo :: CString -> Word32 -> Word32

main = do
	bar <- foo <+ withCString "Hello, world."
	print (bar 42)

... same problem as above.

Cheers,

Wolfgang




More information about the FFI mailing list