Ticket #1212 (new defect)

Opened 3 years ago

Last modified 3 years ago

Button Printf Callback Fails

Reported by: guest Owned by: somebody
Priority: normal Milestone:
Component: general (Gtk+, Glib) Version:
Keywords: printf button callback Cc:


The version was 0.12 (not listed as an option).

If I include any call to printf (from Text.Printf) within a button callback, I get a "gtk2hs_closure_marshal: uncaught exception" and the program terminates. The failure does not seem to happen with other non-button callbacks and it also does not fail for other string printing functions like putStrLn.

The equivalent code in C works fine. I've attached both a C and haskell version for comparison.


test.hs (483 bytes) - added by guest 3 years ago.
Buggy Haskell Version
test.c (0.7 kB) - added by guest 3 years ago.
Equivalent C Version

Change History

Changed 3 years ago by guest

Buggy Haskell Version

Changed 3 years ago by guest

Equivalent C Version

Changed 3 years ago by guest

Ok, I'm closer to solving it. Basically, when debugging the exception raised in ghci, it came up as a Prelude.undefined exception. The source of the undefined exception is in the printf code, specifically in the following segment:

instance PrintfType (IO a) where
    spr fmts args = do
	putStr (uprintf fmts (reverse args))
	return undefined

This explains why the equivalent code with "putStr" instead of printf does not have any problems. I'm not sure exactly why they wrote it as an instance of IO a and not IO (). I'll look into that more.

Either way, something in the gtk code is trying to evaluate the return code which is causing the exception to be raised. A simple ghci session illustrates the difference:

Prelude Text.Printf> e <- putStr "Hey\n" :: IO ()
Prelude Text.Printf> e
Prelude Text.Printf> e <- printf "Hey\n" :: IO ()
Prelude Text.Printf> e
*** Exception: Prelude.undefined

So the problem is that gtk is somehow evaluating the value bound from the user-supplied callback, even if it's a void callback, but printf's weird instance screws that up and returns undefined instead of (). I'm not sure whether I should consider this a bug in gtk or printf, but I'm guessing printf. Any feedback would be appreciated.

Changed 3 years ago by guest

Ok, so the source of the problem is in System.Glib's hsgclosure.c in the gtk2hs_closure_marshal function, specifically in the use of rts_evalIO, which evaluates the IO's result to WHNF, but since it's undefined this raises the exception and crashes the program. I'm going to try out the rts_evalLazyIO replacement and see if that fixes the problem.

In the meantime, I'd like to ask the developers why they use the strict evaluation instead of the lazy one. Is it to prevent space leaks?

Also, I don't know how to create an account for this bug tracking system so I've been using the anonymous login, but if anybody wants to contact me, my e-mail is GabrielNUMBER@… (replace NUMBER with 439 so you get Gabriel439).

Changed 3 years ago by guest

Oops, it mangled my e-mail address. It should begin with Gabriel439 and end with gmail.com.

Changed 3 years ago by guest

Alright, I proved that it works. If you change rts_evalIO to rts_evalLazyIO in hsgclosure.c of glib, it fixed the problem completely. Since nobody has responded so far, I'm going to try the gtk2hs-devel mailing list to see if there is any reason why they have it as the strict evaluation.

There seem to be 3 possible solutions to the problem:

  • patch glib (using rts_evalLazyIO to lazily evaluate IO return values)
  • patch printf so that it uses the FlexibleInstances? extension so that it doesn't have to return undefined values
  • Figure out how to make it so that ghc converts the return value of printf to GHC.Prim.Any instead of undefined
Note: See TracTickets for help on using tickets.