FFI Bug - Finalizer always called with NULL pointer?

Hi - I've discovered that the finalizer in the code below is always called with a NULL pointer even though the pointer returned by the allocation routine is always not NULL. Is this a known bug, and if so, are there any workarounds? I'm using ghc version 6.4: data RawFont newtype Font = Font (ForeignPtr RawFont) foreign import ccall duma_createFont :: CString -> Int -> Bool -> Bool -> Bool -> IO (Ptr RawFont) foreign import ccall duma_releaseFont :: FunPtr (Ptr RawFont -> IO ()) createFont :: String -> Int -> Bool -> Bool -> Bool -> IO Font createFont name pointSize bold italic underline = block $ do f <- (withCString name $ \cname -> duma_createFont cname pointSize bold italic underline) >>= newForeignPtr duma_releaseFont -- Gets a NULL pointer!!! return $ Font f Thanks, Brian.

Hi - When I use -O2 to compile, gcc gives a compilation error: too few arguments to function "duma_releaseFont" When I look at the ghc output with -ddump-cmm, this seems to be where the bug is: r2MP_entry() { // SNIP - all kinds of stuff here call "ccall" suspendThread((BaseReg, NoHint))[(_c36U, NoHint)]; call "ccall" duma_releaseFont()[(_c36V, PtrHint)]; -- @@@@ MISSING ARG call "ccall" resumeThread((_c36U, NoHint)); // SNIP more stuff jump stg_gc_enter_1; } So ghc is not using supplying an argument when it should be supplying duma_releaseFont with the raw pointer contained inside the ForeignPtr being garbage collected. This also explains why the program crashes even with native compilation (debug build). So the bug is not that it is supplying a NULL arg but that it is not supplying any arg in the first place. I've also tried using addForeignPtrFinalizer instead but this doesn't help: GHC is determined to not give the finalizer any argument. createFont name pointSize bold italic underline = block $ do fRaw <- (withCString name $ \cname -> duma_createFont cname pointSize bold italic underline) f <- newForeignPtr_ fRaw addForeignPtrFinalizer duma_releaseFont f -- no luck either return $ Font f Regards, Brian.

Solved! By just using the following syntax, GHC compiles everything correctly: foreign import ccall "&duma_releaseFont" -- absolutely vital for FunPtr functions duma_releaseFont :: FunPtr (Ptr RawFont -> IO ()) which now gives (correctly): s36c_entry() { // SNIP call "ccall" suspendThread((BaseReg, NoHint))[(_c3be, NoHint)]; call "ccall" duma_releaseFont((_s365, PtrHint)); // SPLENDID WORK GHC !!!! :-)))) call "ccall" resumeThread((_c3be, NoHint)); So it seems there is something ***very*** special about the "&duma_releaseFont" syntax whereas I'd have thought that the meaning of: foreign import ccall duma_releaseFont :: FunPtr (Ptr RawFont -> IO ()) -- DANGEROUSLY BAD :-( should be absolutely identical. However it is not. I'm not sure whether or not to report this as a bug since it certainly tripped me up, and it was only by some lucky detective work that I discovered what was happening. Is there supposed to be a difference or is this just a bug? In any case - problem solved, Brian.

[Helpful off-list suggestion to look at FFI spec for & more closely]
Thanks. I'd read it several times before but hadn't understood the difference between a function and the address of a function and so thought '&' was optional, as it is in C for functions: void foo(); typedef void (*Fun)(); Fun a = &foo; Fun b = foo; // same as above (in VC7) However I see now that in the Haskell FFI my original declaration, without the &, was declaring duma_releaseFont to be a function taking no args and returning a FunPtr, whereas with the &, I am declaring duma_releaseFont to be the FunPtr itself. The '&' is needed because otherwise there would be no way to distinguish the wrapping of a C function in a FunPtr and a C function returning a FunPtr. So in a way it is "obvious" but only when it is realised that '&' actually means something in Haskell FFI even though it is irrelevant (when taking about functions) in C. Therefore there is no bug anywhere. It is just that FFI has a high learning curve since it rests on extremely subtle but vital distinctions foreign to a C programmer... :-)

Hello Brian, Saturday, April 8, 2006, 1:35:06 PM, you wrote:
Fun a = &foo; Fun b = foo; // same as above (in VC7)
Therefore there is no bug anywhere. It is just that FFI has a high learning curve since it rests on extremely subtle but vital distinctions foreign to a C programmer... :-)
sorry but you just not very good know C. in the second case C _implicitly_ converts "foo" to the "&foo", i.e. take address of function instead of calling it -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Brian Hulley wrote:
Solved! By just using the following syntax, GHC compiles everything correctly:
foreign import ccall "&duma_releaseFont" -- absolutely vital for FunPtr functions duma_releaseFont :: FunPtr (Ptr RawFont -> IO ())
Yes, you're not the first person to trip over this one. I've done it myself, and it caused much head-scratching. I think we should probably emit a warning in this case - it's much more likely that you meant to import "&foo" as a FunPtr, than just "foo". Cheers, Simon
participants (3)
-
Brian Hulley
-
Bulat Ziganshin
-
Simon Marlow