#5653: "throw" in IO monad is incorrectly optimized away
---------------------------------+------------------------------------------
Reporter: quark | Owner:
Type: bug | Status: new
Priority: normal | Component: Compiler
Version: 6.12.3 | Keywords:
Testcase: | Blockedby:
Os: Unknown/Multiple | Blocking:
Architecture: Unknown/Multiple | Failure: Incorrect result at runtime
---------------------------------+------------------------------------------
In this example program, if I set things up just right, GHC will
incorrectly execute a function on the IO monad. I can get GHC to execute
it properly by removing an unnecessary Id from the export list (!!), by
removing some complexity in the function (removing if-stmts, for example),
or by inserting a trace statement.
On Linux machines (both 32-bit and 64-bit): This bug occurs with GHC
6.12.3 and 6.12.1. It does not occur with 6.8.2 or with 7, but I do not
know if this is because the bug was fixed or perhaps the bug is not
triggered. Therefore, I'm attaching this example, so that you can
identify the source of the bug, and then judge whether it still exists in
GHC 7.
I have tested on Mac OS X with GHC 6.10.4 and the bug does not occur
there.
In the attached tar-ball, just type "make" and it will build the
executable "Main" from "Main.hs". This program calls an IO monad function
in "Wrap.hs", which has several execution paths through it, but one path
throws an error, using a function in "Error.hs" (and this is the path that
"Main" stimulates). The other files are for data types used by "Wrap". I
have attempted to reduce these files to only what is needed. Note that
the "Id" type needs to use SpeedyString, or else the bug isn't triggered.
When you run "Main", you get this:
# ./Main
Num elements before (expect 1): 1
Num elements after (expect 1): 0
IF YOU SEE THIS MESSAGE, GHC HAS A BUG
In "addWrap", the first trace shows that the list "is" has one element.
When we "concatMapM" over the list, it should still have one element.
There is no branch that would produce zero elements, and yet that's what
GHC did! If GHC had properly executed the monad statements, then the call
to "err" would have thrown an error, looking like this:
# ./Main
Num elements before (expect 1): 1
Main: Normal user error
You can get GHC to produce this correct behavior in several ways. One is
to uncomment (and thus add in) the trace statement right before the call
to "err":
traceM("reached error")
Another way to get the correct behavior is to remove the export of
"unsafeMessageExit" from "Error.hs"! How odd! That function is not used
anywhere, but maybe it's existence adds more users of "throw" which
changes GHC's use analysis or something?
And, of course, you can prevent the bug by simplifying the program in
various ways. Removing some if-expressions or case-expressions from
"Wrap" will do it. Note that even just leaving in if-expressions that
have the same value in both arms (such as the definition of "r_ctxs") will
trigger the bug!
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/5653>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs