Skip to content

Hello World Bug - silent stdout errors

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

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

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!

Trac metadata
Trac field Value
Version 7.10.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information