From: Jules B. <ju...@je...> - 2008-03-14 09:51:59
|
Eric Y. Kow wrote: > I have honestly no idea what's going on here. I've worked it out. With a little help from malcolmw on #ghc. 1 image <- imageCreateSized (WX.Size 256 256) 2 pixels <- imageGetData image 3 bytes <- peekArray (256*256*3) (castPtr pixels) After line 2 is executed, there is no remaining reference to 'image' in the program. 'image' is dead, and can be garbage collected. (Although it may not be at any particular time). If 'image' gets GC'ed, because there is a ForeignPtr inside, that calls the C++ destructor. The wxImage C++ destructor believes it owns the data block, so it free()s it, and 'pixels' is left pointing to a free()ed block. This is why it is inconsistent. It depends if image happens to get GC'ed before the peekArray completes running. As to how we fix it? Well as a proof of concept, adding: putStrLn $ "Keep image alive with this reference " ++ (show image) as the last line of createAndGetPixels will prevent the GC and stop the segfault. The right fix tho? I'm not sure. It seems like 'imageGetData' is fundamentally broken (and thus anything that depends on it, like getPixels). Is there some way imageGetData could return a Ptr and simultaneously keep the 'image' alive for as long as the Ptr is alive? Should imageGetData be turned into a 'with-style' function Image a -> (Ptr () -> IO b) -> IO b which protects the image? Is there a workaround I can use in my code like touchPtr? A version of touchPtr which works on WXObjects? Jules |