[GHC] #11836: Hello World Bug - silent stdout errors

GHC ghc-devs at haskell.org
Thu Apr 14 17:36:28 UTC 2016


#11836: Hello World Bug - silent stdout errors
-------------------------------------+-------------------------------------
           Reporter:  bit            |             Owner:
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  7.10.3
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 == Background

 This entertaining talk explains the issue: https://www.irill.org/events
 /ghm-gnu-hackers-meeting/videos/jim-meyering-goodbye-world-the-perils-of-
 relying-on-output-streams-in-c

 == hello.hs
 {{{#!hs
 main = putStrLn "Hello world"
 }}}

 == Run it

 {{{
 $ runhaskell hello.hs > /dev/full ; echo $?
 hello.hs: <stdout>: hPutChar: resource exhausted (No space left on device)
 1
 }}}

 That looks good! We tried to save the output to a file but the disk was
 full, so we got an error message, and a process exit code indicating
 failure.

 == Run it compiled

 {{{
 $ ghc hello.hs
 $ ./hello > /dev/full ; echo $?
 0
 }}}

 Not good! The error was silently ignored, and additionally the process
 lied when it reported a successful exit status.

 Why did it behave differently when compiled? When `runhaskell` is used,
 the buffering of stdout is `NoBuffering` therefore the putStrLn call
 fails. But when compiled, stdout is in `LineBuffering` mode and therefore
 the putStrLn call succeeds.

 The fix:

 == hello2.hs
 {{{#!hs
 import System.IO

 main = do
     putStrLn "Hello world"
     hClose stdout
 }}}

 == Run it compiled

 {{{
 $ ghc hello2.hs
 $ ./hello2 > /dev/full ; echo $?
 hello: <stdout>: hClose: resource exhausted (No space left on device)
 1
 }}}

 Looks good! But there's a catch:

 {{{
 $ runhaskell hello2.hs ; echo $?
 Hello world
 ghc: <stdout>: hFlush: illegal operation (handle is closed)
 1
 }}}

 Now our program fails to run correctly with `runhaskell` :(

 It seems that `runhaskell` is running some hidden code after main
 finished. It is not clear to me how to write a correct "Hello World" that
 works both compiled and with `runhaskell`.

 == Summary

 One of the greatest things about Haskell is that short, clear and concise
 programs can also be correct.

 It is my opinion that the original "hello.hs" should Just Work™. Haskell
 programmers shouldn't have to know that they need to always close stdout
 before exiting. Especially since it's not even clear how to do it
 properly...

 Thank you!

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11836>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list