If someone wouldn’t mind sanity checking this for me, I want to make sure that this initialization pattern is sane and doesn’t leak:
-- typedef struct botan_foo_struct* botan_foo_t;
type OpaqueFoo = Ptr ()
newtype Foo = Foo { fooForeignPtr :: ForeignPtr OpaqueFoo }
-- int botan_foo_init(botan_foo_t* foo);
foreign import ccall unsafe botan_foo_init :: Ptr OpaqueFoo -> IO BotanErrorCode
-- int botan_foo_destroy(botan_foo_t foo);
foreign import ccall "&botan_foo_destroy" botan_foo_destroy :: FunPtr (Ptr OpaqueFoo -> IO ())
fooInit :: IO Foo
fooInit name = do
fooForeignPtr <- malloc >>= newForeignPtr botan_foo_destroy
withForeignPtr fooForeignPtr $ \ fooPtr -> do
throwBotanIfNegative_ $ botan_foo_init fooPtr
return $ Foo fooForeignPtr
My concern is that Botan
's design is to pass a pointer-pointer in to the initializer and return an success-error code, rather than return an initialized pointer. Being unfamiliar with ForeignPtr
, I want to ensure that the pointer that we malloc
for use with botan_foo_init
is itself destroyed with botan_foo_destroy
when the ForeignPtr
is garbage collected, and not just the opaque object that it was pointing to.
I think this is correct, because when I used alloca
instead of malloc
(because I was replacing ByteArray.alloc
), I got exceptions because long-lived references were having their pointers freed - but what I don’t want now is the opposite problem of leaking memory. I made the swap to malloc
after reading the docs more closely (and checking the source of ByteArray.alloc
revealed that it actually used mallocByteString
, too).
So now, I am not observing any faulty behavior, but I’d surely appreciate a sanity check from another set of eyes.