GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T18:37:03Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/10215Optimizer has bugs regarding handling of -0.02019-07-07T18:37:03ZLevent ErkökOptimizer has bugs regarding handling of -0.0This is most likely related to #9238
Perhaps it can be merged into that if it is indeed the case, though it'd be good for an expert to take a look and make sure first that the culprit is indeed the same. In any case, the program in this...This is most likely related to #9238
Perhaps it can be merged into that if it is indeed the case, though it'd be good for an expert to take a look and make sure first that the culprit is indeed the same. In any case, the program in this ticket can at least serve as a test-case.
I observed this on 7.8.3; though I suspect the same holds in the just released 7.10.1 as well.
For the following program:
```hs
testF :: Float -> Bool
testF x = x == 0 && not (isNegativeZero x)
testD :: Double -> Bool
testD x = x == 0 && not (isNegativeZero x)
main :: IO ()
main = do print $ testF (-0.0)
print $ testD (-0.0)
```
If I compile with no optimizations, then I get the correct answers:
```
$ /bin/rm -f a.hi a.o a; ghc -O0 a; ./a
[1 of 1] Compiling Main ( a.hs, a.o )
Linking a ...
False
False
```
But if I turn optimizations on, then I get:
```
$ /bin/rm -f a.hi a.o a; ghc -O2 a; ./a
[1 of 1] Compiling Main ( a.hs, a.o )
Linking a ...
True
True
```
which is just plain wrong.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Optimizer has bugs regarding handling of -0.0","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"This is most likely related to https://ghc.haskell.org/trac/ghc/ticket/9238\r\n\r\nPerhaps it can be merged into that if it is indeed the case, though it'd be good for an expert to take a look and make sure first that the culprit is indeed the same. In any case, the program in this ticket can at least serve as a test-case.\r\n\r\nI observed this on 7.8.3; though I suspect the same holds in the just released 7.10.1 as well.\r\nFor the following program:\r\n\r\n{{{#!hs\r\ntestF :: Float -> Bool\r\ntestF x = x == 0 && not (isNegativeZero x)\r\n\r\ntestD :: Double -> Bool\r\ntestD x = x == 0 && not (isNegativeZero x)\r\n\r\nmain :: IO ()\r\nmain = do print $ testF (-0.0)\r\n print $ testD (-0.0)\r\n}}}\r\n\r\nIf I compile with no optimizations, then I get the correct answers:\r\n{{{\r\n$ /bin/rm -f a.hi a.o a; ghc -O0 a; ./a\r\n[1 of 1] Compiling Main ( a.hs, a.o )\r\nLinking a ...\r\nFalse\r\nFalse\r\n}}}\r\n\r\nBut if I turn optimizations on, then I get:\r\n{{{\r\n$ /bin/rm -f a.hi a.o a; ghc -O2 a; ./a\r\n[1 of 1] Compiling Main ( a.hs, a.o )\r\nLinking a ...\r\nTrue\r\nTrue\r\n}}}\r\n\r\nwhich is just plain wrong. ","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/10007Fix misattribution of Cost Centre profiles to lintAnnots2019-07-07T18:37:57ZthoughtpoliceFix misattribution of Cost Centre profiles to lintAnnotsSplit off from #9961 - the profiling results while debugging erroneously reported that most cost centre profiles were a result of `lintAnnots`, as opposed to `CSE`. This is a bug.
<details><summary>Trac metadata</summary>
| Trac field ...Split off from #9961 - the profiling results while debugging erroneously reported that most cost centre profiles were a result of `lintAnnots`, as opposed to `CSE`. This is a bug.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------------------------------------- |
| Version | 7.10.1-rc1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Profiling |
| Test case | |
| Differential revisions | [D616](https://phabricator.haskell.org/D616) |
| BlockedBy | |
| Related | #9961 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Fix misattribution of Cost Centre profiles to lintAnnots","status":"New","operating_system":"","component":"Profiling","related":[9961],"milestone":"7.10.1","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"scpmw"},"version":"7.10.1-rc1","keywords":[],"differentials":[616],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Split off from #9961 - the profiling results while debugging erroneously reported that most cost centre profiles were a result of `lintAnnots`, as opposed to `CSE`. This is a bug.","type_of_failure":"OtherFailure","blocking":[]} -->8.2.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/9955ghc-stage1 compiles with bootstrapping ghc package, not the built one2019-07-07T18:38:13ZEdward Z. Yangghc-stage1 compiles with bootstrapping ghc package, not the built oneSteps to reproduce: Build GHC using 7.10 as the bootstrapping compiler. Now check which GHC package stage 1 Main.hi was linked against, e.g. using `--show-iface`:
```
[ezyang@hs01 ghc-validate2]$ ../ghc-7.10/inplace/bin/ghc-stage2 --sho...Steps to reproduce: Build GHC using 7.10 as the bootstrapping compiler. Now check which GHC package stage 1 Main.hi was linked against, e.g. using `--show-iface`:
```
[ezyang@hs01 ghc-validate2]$ ../ghc-7.10/inplace/bin/ghc-stage2 --show-iface ghc/stage1/build/Main.hi
...
package dependencies: array-0.5.0.1 base-4.8.0.0 binary-0.7.2.3
bin-package-db-0.0.0.0 bytestring-0.10.6.0 containers-0.5.6.2
deepseq-1.4.0.0 directory-1.2.1.1 filepath-1.3.1.0
ghc-7.10.0.20141223 ghc-prim-0.3.1.0 hoopl-3.10.0.2 hpc-0.6.0.2
integer-gmp-1.0.0.0 process-1.2.1.0 time-1.5.0.1
transformers-0.4.2.0 unix-2.7.1.0
```
Bad news!
I think I introduced bug when I made GHC a wired in package: consequently when we ask GHC to link against a specific version of the GHC package, this flag is ignored. I don't actually know what the right way to fix this is, but we'll have to figure something out here.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.11 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | highest |
| Resolution | Unresolved |
| Component | Build System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"ghc-stage1 compiles with bootstrapping ghc package, not the built one","status":"New","operating_system":"","component":"Build System","related":[],"milestone":"7.10.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.11","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Steps to reproduce: Build GHC using 7.10 as the bootstrapping compiler. Now check which GHC package stage 1 Main.hi was linked against, e.g. using `--show-iface`:\r\n\r\n{{{\r\n[ezyang@hs01 ghc-validate2]$ ../ghc-7.10/inplace/bin/ghc-stage2 --show-iface ghc/stage1/build/Main.hi\r\n...\r\npackage dependencies: array-0.5.0.1 base-4.8.0.0 binary-0.7.2.3\r\n bin-package-db-0.0.0.0 bytestring-0.10.6.0 containers-0.5.6.2\r\n deepseq-1.4.0.0 directory-1.2.1.1 filepath-1.3.1.0\r\n ghc-7.10.0.20141223 ghc-prim-0.3.1.0 hoopl-3.10.0.2 hpc-0.6.0.2\r\n integer-gmp-1.0.0.0 process-1.2.1.0 time-1.5.0.1\r\n transformers-0.4.2.0 unix-2.7.1.0\r\n}}}\r\n\r\nBad news!\r\n\r\nI think I introduced bug when I made GHC a wired in package: consequently when we ask GHC to link against a specific version of the GHC package, this flag is ignored. I don't actually know what the right way to fix this is, but we'll have to figure something out here.","type_of_failure":"OtherFailure","blocking":[]} -->7.10.1https://gitlab.haskell.org/ghc/ghc/-/issues/9533Signed/unsigned integer difference between compiled and interpreted code2019-07-07T18:40:08ZMichaelBurgeSigned/unsigned integer difference between compiled and interpreted codeThe following code outputs "A".
```hs
import Data.Word
x :: Word
x = 10
y :: Word
y = 11
test = case x - y of
-1 -> "A"
_ -> "B"
main = putStrLn $ show test
```
However, adding a new case that isn't matched causes...The following code outputs "A".
```hs
import Data.Word
x :: Word
x = 10
y :: Word
y = 11
test = case x - y of
-1 -> "A"
_ -> "B"
main = putStrLn $ show test
```
However, adding a new case that isn't matched causes the output to change:
```hs
import Data.Word
x :: Word
x = 10
y :: Word
y = 11
test = case x - y of
5 -> "C"
-1 -> "A"
_ -> "B"
main = putStrLn $ show test
```
With the extra '5 -\> "C"' line in the case, the output is "B".
It gets weirder - interpreted code actually continues to match the -1 case. With the second example in a file 'T.hs', here is a GHCi session:
```
Prelude Main> :l *T.hs
[1 of 1] Compiling Main ( T.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
"A"
*Main> :l T.hs
Ok, modules loaded: Main.
Prelude Main> main
"B"
Prelude Main>
```
These examples suggest to me at least 3 improvements:
- Issue a warning when a negative number is used in a case statement in unsigned context
- Interpreted code should give the same result as compiled code
- Adding a case that isn't matched shouldn't change which other patterns get matched
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Windows |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Signed/unsigned integer difference between compiled and interpreted code","status":"New","operating_system":"Windows","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following code outputs \"A\".\r\n{{{#!hs\r\nimport Data.Word\r\n\r\nx :: Word\r\nx = 10\r\n\r\ny :: Word\r\ny = 11\r\n\r\ntest = case x - y of\r\n -1 -> \"A\"\r\n _ -> \"B\"\r\nmain = putStrLn $ show test\r\n}}}\r\n\r\nHowever, adding a new case that isn't matched causes the output to change:\r\n{{{#!hs\r\nimport Data.Word\r\n\r\nx :: Word\r\nx = 10\r\n\r\ny :: Word\r\ny = 11\r\n\r\ntest = case x - y of\r\n 5 -> \"C\"\r\n -1 -> \"A\"\r\n _ -> \"B\"\r\nmain = putStrLn $ show test\r\n}}}\r\n\r\nWith the extra '5 -> \"C\"' line in the case, the output is \"B\".\r\n\r\nIt gets weirder - interpreted code actually continues to match the -1 case. With the second example in a file 'T.hs', here is a GHCi session:\r\n{{{\r\nPrelude Main> :l *T.hs\r\n[1 of 1] Compiling Main ( T.hs, interpreted )\r\nOk, modules loaded: Main.\r\n*Main> main\r\n\"A\"\r\n*Main> :l T.hs\r\nOk, modules loaded: Main.\r\nPrelude Main> main\r\n\"B\"\r\nPrelude Main>\r\n}}}\r\n\r\nThese examples suggest to me at least 3 improvements:\r\n* Issue a warning when a negative number is used in a case statement in unsigned context\r\n* Interpreted code should give the same result as compiled code\r\n* Adding a case that isn't matched shouldn't change which other patterns get matched","type_of_failure":"OtherFailure","blocking":[]} -->8.2.1https://gitlab.haskell.org/ghc/ghc/-/issues/9454Unregisterized builds failing due to multiple uniques assigned to same FastSt...2019-07-07T18:40:20ZEdward Z. YangUnregisterized builds failing due to multiple uniques assigned to same FastStringWhen compiling with `--enable-unregisterised`, we get this failure:
```
"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -H32m -O -this-package-key conta_4P4
dHnD3A89EkvERxmaFmd -hide-all-packages -i -ilibraries/contain...When compiling with `--enable-unregisterised`, we get this failure:
```
"inplace/bin/ghc-stage1" -hisuf hi -osuf o -hcsuf hc -static -H32m -O -this-package-key conta_4P4
dHnD3A89EkvERxmaFmd -hide-all-packages -i -ilibraries/containers/. -ilibraries/containers/dist-install
/build -ilibraries/containers/dist-install/build/autogen -Ilibraries/containers/dist-install/build -Il
ibraries/containers/dist-install/build/autogen -Ilibraries/containers/include -optP-include -optPli
braries/containers/dist-install/build/autogen/cabal_macros.h -package-key array_H3W2D8UaI9TKGEhUuQHax2
-package-key base_DiPQ1siqG3SBjHauL3L03p -package-key deeps_L0rJEVU1Zgn8x0Qs5aTOsU -package-key ghcpr
_BE58KUgBe9ELCsPXiJ1Q2r -O2 -Wall -XHaskell98 -XRoleAnnotations -O2 -no-user-package-db -rtsopts
-odir libraries/containers/dist-install/build -hidir libraries/containers/dist-install/build -stubdir
libraries/containers/dist-install/build -dynamic-too -c libraries/containers/./Data/StrictPair.hs -o
libraries/containers/dist-install/build/Data/StrictPair.o -dyno libraries/containers/dist-install/bui
ld/Data/StrictPair.dyn_o
<command line>: unknown package: deepseq-1.3.0.2
```
The reason why GHC is unable to find the package is because, as it turns out, the Unique that was used to store the key in a map is different from the Unique associated with the FastString that we're doing the lookup with.
The bug only shows up with ghc-stage1 is compiled with optimizations.
Bisecting revealed that this commit was to blame:
```
commit 66218d15b7c27a4a38992003bd761f60bae84b1f
Author: Edward Z. Yang <ezyang@cs.stanford.edu>
Date: Fri Jul 18 14:48:47 2014 +0100
Package keys (for linking/type equality) separated from package IDs.
```
However, looking at the commit, there is nothing that would obviously cause this problem, so maybe it is tickling a preexisting bug.
Bisection script:
{{{
\#!/bin/sh
make clean
git submodule update
perl boot
1. /configure --enable-unregisterised
make -j11 libraries/containers/dist-install/build/Data/StrictPair.o
}}}
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.9 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Unregisterized builds failing due to multiple uniques assigned to same FastString","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"ezyang"},"version":"7.9","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When compiling with `--enable-unregisterised`, we get this failure:\r\n\r\n{{{\r\n\"inplace/bin/ghc-stage1\" -hisuf hi -osuf o -hcsuf hc -static -H32m -O -this-package-key conta_4P4\r\ndHnD3A89EkvERxmaFmd -hide-all-packages -i -ilibraries/containers/. -ilibraries/containers/dist-install\r\n/build -ilibraries/containers/dist-install/build/autogen -Ilibraries/containers/dist-install/build -Il\r\nibraries/containers/dist-install/build/autogen -Ilibraries/containers/include -optP-include -optPli\r\nbraries/containers/dist-install/build/autogen/cabal_macros.h -package-key array_H3W2D8UaI9TKGEhUuQHax2\r\n -package-key base_DiPQ1siqG3SBjHauL3L03p -package-key deeps_L0rJEVU1Zgn8x0Qs5aTOsU -package-key ghcpr\r\n_BE58KUgBe9ELCsPXiJ1Q2r -O2 -Wall -XHaskell98 -XRoleAnnotations -O2 -no-user-package-db -rtsopts \r\n -odir libraries/containers/dist-install/build -hidir libraries/containers/dist-install/build -stubdir\r\n libraries/containers/dist-install/build -dynamic-too -c libraries/containers/./Data/StrictPair.hs -o\r\n libraries/containers/dist-install/build/Data/StrictPair.o -dyno libraries/containers/dist-install/bui\r\nld/Data/StrictPair.dyn_o\r\n<command line>: unknown package: deepseq-1.3.0.2\r\n}}}\r\n\r\nThe reason why GHC is unable to find the package is because, as it turns out, the Unique that was used to store the key in a map is different from the Unique associated with the FastString that we're doing the lookup with.\r\n\r\nThe bug only shows up with ghc-stage1 is compiled with optimizations.\r\n\r\nBisecting revealed that this commit was to blame:\r\n\r\n{{{\r\ncommit 66218d15b7c27a4a38992003bd761f60bae84b1f\r\nAuthor: Edward Z. Yang <ezyang@cs.stanford.edu>\r\nDate: Fri Jul 18 14:48:47 2014 +0100\r\n\r\n Package keys (for linking/type equality) separated from package IDs.\r\n}}}\r\n\r\nHowever, looking at the commit, there is nothing that would obviously cause this problem, so maybe it is tickling a preexisting bug.\r\n\r\nBisection script:\r\n\r\n{{{\r\n#!/bin/sh\r\nmake clean\r\ngit submodule update\r\nperl boot\r\n./configure --enable-unregisterised\r\nmake -j11 libraries/containers/dist-install/build/Data/StrictPair.o\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->Edward Z. YangEdward Z. Yanghttps://gitlab.haskell.org/ghc/ghc/-/issues/9384setNumCapabilities call breaks eventlog events2019-07-07T18:40:37ZSergei TrofimovichsetNumCapabilities call breaks eventlog eventsThe problem was found when i tried to eventlog **ghc --make** itself.
I've missinterpreted is as a threadscope bug: https://github.com/haskell/ThreadScope/issues/37
Here is small program to reliably reproduce the bug:
```hs
module Main...The problem was found when i tried to eventlog **ghc --make** itself.
I've missinterpreted is as a threadscope bug: https://github.com/haskell/ThreadScope/issues/37
Here is small program to reliably reproduce the bug:
```hs
module Main where
import qualified Data.List as L
import qualified System.Environment as E
import Control.Monad
import qualified Control.Concurrent as CC
import qualified Control.Concurrent.MVar as CC
slow_and_silly :: Int -> IO Int
slow_and_silly i = return $ length $ L.foldl' (\a v -> a ++ [v]) [] [1..i]
-- build as:
-- $ ghc --make a -O2 -threaded -eventlog
-- valid eventlog:
-- $ ./a 2 7000 +RTS -ls -N2
-- $ ghc-events validate threads a.eventlog
-- Valid eventlog:
-- ...
-- invalid eventlog
-- $ ./a 2 7000 +RTS -ls
-- $ ghc-events validate threads a.eventlog
-- Invalid eventlog:
-- ...
main = do
[caps, count] <- E.getArgs
let n_caps :: Int
n_caps = read caps
max_n :: Int
max_n = read count
CC.setNumCapabilities n_caps
waits <- replicateM n_caps $ CC.newEmptyMVar
forM_ waits $ \w -> CC.forkIO $ do
slow_and_silly max_n >>= print
CC.putMVar w ()
forM_ waits $ \w -> CC.takeMVar w
```
How to reproduce (comments have **ghc-events** version):
```
$ ghc --make a -O2 -threaded -eventlog
$ ./a 2 7000 +RTS -ls -N2
$ threadscope a.eventlog # works
$ ./a 2 7000 +RTS -ls
$ threadscope a.eventlog # crashes
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Profiling |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"setNumCapabilities call breaks eventlog events","status":"New","operating_system":"","component":"Profiling","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The problem was found when i tried to eventlog '''ghc --make''' itself.\r\nI've missinterpreted is as a threadscope bug: https://github.com/haskell/ThreadScope/issues/37\r\n\r\nHere is small program to reliably reproduce the bug:\r\n\r\n{{{#!hs\r\nmodule Main where\r\n\r\nimport qualified Data.List as L\r\nimport qualified System.Environment as E\r\nimport Control.Monad\r\nimport qualified Control.Concurrent as CC\r\nimport qualified Control.Concurrent.MVar as CC\r\n\r\nslow_and_silly :: Int -> IO Int\r\nslow_and_silly i = return $ length $ L.foldl' (\\a v -> a ++ [v]) [] [1..i]\r\n\r\n-- build as:\r\n-- $ ghc --make a -O2 -threaded -eventlog\r\n\r\n-- valid eventlog:\r\n-- $ ./a 2 7000 +RTS -ls -N2\r\n-- $ ghc-events validate threads a.eventlog\r\n-- Valid eventlog:\r\n-- ...\r\n\r\n-- invalid eventlog\r\n-- $ ./a 2 7000 +RTS -ls\r\n-- $ ghc-events validate threads a.eventlog\r\n-- Invalid eventlog:\r\n-- ...\r\n\r\nmain = do\r\n [caps, count] <- E.getArgs\r\n let n_caps :: Int\r\n n_caps = read caps\r\n max_n :: Int\r\n max_n = read count\r\n\r\n CC.setNumCapabilities n_caps\r\n\r\n waits <- replicateM n_caps $ CC.newEmptyMVar\r\n\r\n forM_ waits $ \\w -> CC.forkIO $ do\r\n slow_and_silly max_n >>= print\r\n CC.putMVar w ()\r\n\r\n forM_ waits $ \\w -> CC.takeMVar w\r\n}}}\r\n\r\nHow to reproduce (comments have '''ghc-events''' version):\r\n{{{\r\n$ ghc --make a -O2 -threaded -eventlog\r\n$ ./a 2 7000 +RTS -ls -N2\r\n$ threadscope a.eventlog # works\r\n$ ./a 2 7000 +RTS -ls\r\n$ threadscope a.eventlog # crashes\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->7.10.1https://gitlab.haskell.org/ghc/ghc/-/issues/9125int-to-float conversion broken on ARM2019-07-07T18:41:47ZAnsibleint-to-float conversion broken on ARMI compiled ghc on the raspberry pi. See this bug for more about that build of ghc: [8896](https://ghc.haskell.org/trac/ghc/ticket/8896).
A simple test program:
```
main = do
mapM_ (print . (fromInteger :: Integer -> Float)) [0..100]
...I compiled ghc on the raspberry pi. See this bug for more about that build of ghc: [8896](https://ghc.haskell.org/trac/ghc/ticket/8896).
A simple test program:
```
main = do
mapM_ (print . (fromInteger :: Integer -> Float)) [0..100]
```
And the result:
```
0.0
127.0
256.0
257.0
516.0
517.0
518.0
519.0
1040.0
1041.0
1042.0
1043.0
1044.0
1045.0
1046.0
1047.0
2096.0
2097.0
2098.0
2099.0
2100.0
2101.0
2102.0
2103.0
2104.0
2105.0
2106.0
2107.0
2108.0
2109.0
2110.0
2111.0
4224.0
4225.0
4226.0
4227.0
4228.0
4229.0
4230.0
4231.0
4232.0
4233.0
4234.0
4235.0
4236.0
4237.0
4238.0
4239.0
4240.0
4241.0
4242.0
4243.0
4244.0
4245.0
4246.0
4247.0
4248.0
4249.0
4250.0
4251.0
4252.0
4253.0
4254.0
4255.0
8512.0
8513.0
8514.0
8515.0
8516.0
8517.0
8518.0
8519.0
8520.0
8521.0
8522.0
8523.0
8524.0
8525.0
8526.0
8527.0
8528.0
8529.0
8530.0
8531.0
8532.0
8533.0
8534.0
8535.0
8536.0
8537.0
8538.0
8539.0
8540.0
8541.0
8542.0
8543.0
8544.0
8545.0
8546.0
8547.0
8548.0
8538.0
```
This code, however, works normally:
```
main = do
mapM_ (print . (fromInteger :: Integer -> Double)) [0..100]
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Linux |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"int-to-float conversion broken on ARM - 7.8.1-rc2","status":"New","operating_system":"Linux","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I compiled ghc on the raspberry pi. See this bug for more about that build of ghc: [https://ghc.haskell.org/trac/ghc/ticket/8896 8896].\r\n\r\nA simple test program:\r\n\r\n\r\n{{{\r\nmain = do\r\n mapM_ (print . (fromInteger :: Integer -> Float)) [0..100]\r\n\r\n}}}\r\n\r\nAnd the result:\r\n\r\n\r\n{{{\r\n0.0\r\n127.0\r\n256.0\r\n257.0\r\n516.0\r\n517.0\r\n518.0\r\n519.0\r\n1040.0\r\n1041.0\r\n1042.0\r\n1043.0\r\n1044.0\r\n1045.0\r\n1046.0\r\n1047.0\r\n2096.0\r\n2097.0\r\n2098.0\r\n2099.0\r\n2100.0\r\n2101.0\r\n2102.0\r\n2103.0\r\n2104.0\r\n2105.0\r\n2106.0\r\n2107.0\r\n2108.0\r\n2109.0\r\n2110.0\r\n2111.0\r\n4224.0\r\n4225.0\r\n4226.0\r\n4227.0\r\n4228.0\r\n4229.0\r\n4230.0\r\n4231.0\r\n4232.0\r\n4233.0\r\n4234.0\r\n4235.0\r\n4236.0\r\n4237.0\r\n4238.0\r\n4239.0\r\n4240.0\r\n4241.0\r\n4242.0\r\n4243.0\r\n4244.0\r\n4245.0\r\n4246.0\r\n4247.0\r\n4248.0\r\n4249.0\r\n4250.0\r\n4251.0\r\n4252.0\r\n4253.0\r\n4254.0\r\n4255.0\r\n8512.0\r\n8513.0\r\n8514.0\r\n8515.0\r\n8516.0\r\n8517.0\r\n8518.0\r\n8519.0\r\n8520.0\r\n8521.0\r\n8522.0\r\n8523.0\r\n8524.0\r\n8525.0\r\n8526.0\r\n8527.0\r\n8528.0\r\n8529.0\r\n8530.0\r\n8531.0\r\n8532.0\r\n8533.0\r\n8534.0\r\n8535.0\r\n8536.0\r\n8537.0\r\n8538.0\r\n8539.0\r\n8540.0\r\n8541.0\r\n8542.0\r\n8543.0\r\n8544.0\r\n8545.0\r\n8546.0\r\n8547.0\r\n8548.0\r\n8538.0\r\n\r\n}}}\r\n\r\nThis code, however, works normally:\r\n\r\n\r\n{{{\r\nmain = do\r\n mapM_ (print . (fromInteger :: Integer -> Double)) [0..100]\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/8849Unregisterised compiler: arithmetic failure2019-07-07T18:43:07ZPeter Trommlerptrommler@acm.orgUnregisterised compiler: arithmetic failureCompiling the following with RC2 on powerpc 64 downloaded from haskell.org:
```
main = putStr $ show (-1.0000000001 :: Double)
```
Setting `-O` yields:
```
0.0
```
Without optimization the correct result is displayed.
I prepared an ...Compiling the following with RC2 on powerpc 64 downloaded from haskell.org:
```
main = putStr $ show (-1.0000000001 :: Double)
```
Setting `-O` yields:
```
0.0
```
Without optimization the correct result is displayed.
I prepared an unregisterised compiler on amd64 and see the same issue and more arithmetic tests fail in testsuite. In fact I took the above from arith005.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 7.8.1-rc2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown/Multiple |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Unregisterised compiler: arithmetic failure","status":"New","operating_system":"Unknown/Multiple","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.1-rc2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Compiling the following with RC2 on powerpc 64 downloaded from haskell.org:\r\n{{{\r\nmain = putStr $ show (-1.0000000001 :: Double)\r\n}}}\r\nSetting {{{-O}}} yields:\r\n{{{\r\n0.0\r\n}}}\r\nWithout optimization the correct result is displayed.\r\n\r\nI prepared an unregisterised compiler on amd64 and see the same issue and more arithmetic tests fail in testsuite. In fact I took the above from arith005.","type_of_failure":"OtherFailure","blocking":[]} -->7.8.4https://gitlab.haskell.org/ghc/ghc/-/issues/8741`System.Directory.getPermissions` fails on read-only filesystem2019-07-07T18:43:42ZHerbert Valerio Riedelhvr@gnu.org`System.Directory.getPermissions` fails on read-only filesystemAlain O'Dea reports in an [email](http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/21078) that:
```
Prelude> System.Directory.getPermissions "/usr/bin/ld"
*** Exception: /usr/bin/ld: fileAccess: permission denied (Read-only ...Alain O'Dea reports in an [email](http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/21078) that:
```
Prelude> System.Directory.getPermissions "/usr/bin/ld"
*** Exception: /usr/bin/ld: fileAccess: permission denied (Read-only file system)
```
> That seems wrong.
>
> An `access(*, W_OK)` syscall by design should return `EROFS` on a read-only file system by specification.
>
> This breaks Cabal on SmartOS since `/usr` is read-only by design and Cabal calls `getPermissions "/usr/bin/ld"`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | libraries/directory |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"`System.Directory.getPermissions` fails on read-only filesystem","status":"New","operating_system":"","component":"libraries/directory","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Alain O'Dea reports in an [http://permalink.gmane.org/gmane.comp.lang.haskell.libraries/21078 email] that:\r\n\r\n{{{\r\nPrelude> System.Directory.getPermissions \"/usr/bin/ld\"\r\n*** Exception: /usr/bin/ld: fileAccess: permission denied (Read-only file system)\r\n}}}\r\n> That seems wrong.\r\n>\r\n> An `access(*, W_OK)` syscall by design should return `EROFS` on a read-only file system by specification.\r\n>\r\n> This breaks Cabal on SmartOS since `/usr` is read-only by design and Cabal calls `getPermissions \"/usr/bin/ld\"`.","type_of_failure":"OtherFailure","blocking":[]} -->7.8.1AlainODeaAlainODeahttps://gitlab.haskell.org/ghc/ghc/-/issues/87347.8.1 rc1 ghci won't load compiled files2019-07-07T18:43:44Zgeorge.colpitts7.8.1 rc1 ghci won't load compiled files<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.1-rc1 |
| Type | Bug |
| TypeOfFailure |...<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.1-rc1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | GHCi |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | hvr |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"7.8.1 rc1 ghci won't load compiled files","status":"New","operating_system":"","component":"GHCi","related":[],"milestone":"7.8.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.1-rc1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["hvr"],"type":"Bug","description":"","type_of_failure":"OtherFailure","blocking":[]} -->7.8.1https://gitlab.haskell.org/ghc/ghc/-/issues/8702floor, ceiling, truncate and so on… on NaN fail2019-07-07T18:43:53Zphaazonfloor, ceiling, truncate and so on… on NaN failThose functions returns a total random value when given NaN. This is not an acceptable behavior I guess, and we might inquire on what to do.
For instance:
```
let nan = 0 / 0 in floor nan
```
result:
```
-2696539702293473861593957786...Those functions returns a total random value when given NaN. This is not an acceptable behavior I guess, and we might inquire on what to do.
For instance:
```
let nan = 0 / 0 in floor nan
```
result:
```
-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824
```
Maybe an arithmetic exception would be a better behavior?
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"floor, ceiling, truncate and so on… on NaN fail","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Those functions returns a total random value when given NaN. This is not an acceptable behavior I guess, and we might inquire on what to do.\r\n\r\nFor instance:\r\n\r\n\r\n{{{\r\nlet nan = 0 / 0 in floor nan\r\n}}}\r\n\r\nresult:\r\n\r\n{{{\r\n-269653970229347386159395778618353710042696546841345985910145121736599013708251444699062715983611304031680170819807090036488184653221624933739271145959211186566651840137298227914453329401869141179179624428127508653257226023513694322210869665811240855745025766026879447359920868907719574457253034494436336205824\r\n}}}\r\n\r\nMaybe an arithmetic exception would be a better behavior?","type_of_failure":"OtherFailure","blocking":[]} -->⊥https://gitlab.haskell.org/ghc/ghc/-/issues/8669Closed TypeFamilies regression2019-07-07T18:44:01ZMerijn VerstraatenClosed TypeFamilies regressionI first played around with closed typefamilies early 2013 and wrote up the following simple example
```
{-# LANGUAGE ConstraintKinds, DataKinds, PolyKinds, TypeFamilies, TypeOperators #-}
import GHC.Prim (Constraint)
type family Res...I first played around with closed typefamilies early 2013 and wrote up the following simple example
```
{-# LANGUAGE ConstraintKinds, DataKinds, PolyKinds, TypeFamilies, TypeOperators #-}
import GHC.Prim (Constraint)
type family Restrict (a :: k) (as :: [k]) :: Constraint
type instance where
Restrict a (a ': as) = (a ~ "Oops! Tried to apply a restricted type!")
Restrict x (a ': as) = Restrict x as
Restrict x '[] = ()
foo :: Restrict a '[(), Int] => a -> a
foo = id
```
This worked fine, functioning like `id` for types other than `()` and `Int` and returning a type error for `()` and `Int`.
After hearing comments that my example broke when the closed type families syntax changed I decided to update my version of 7.7 and change the code for that. The new code is:
```
{-# LANGUAGE ConstraintKinds, DataKinds, PolyKinds, TypeFamilies, TypeOperators #-}
import GHC.Prim (Constraint)
type family Restrict (a :: k) (as :: [k]) :: Constraint where
Restrict a (a ': as) = (a ~ "Oops! Tried to apply a restricted type!")
Restrict x (a ': as) = Restrict x as
Restrict x '[] = ()
foo :: Restrict a '[(), Int] => a -> a
foo = id
```
This code is accepted by the compiler just fine, but the `Constraint` gets thrown out. When querying ghci for the type of `foo` the following is returned:
```
λ :t foo
foo :: a -> a
λ :i foo
foo :: (Restrict a '[(), Int]) => a -> a
```
Additionally, in the recent 7.7 `foo ()` returns `()` rather than a type error. After some playing around this seems to be caused by the "(a \~ "Oops! Tried to apply a restricted type!")" equality constraint. It seems GHC decides that it doesn't like the fact that types with a polymorphic kind and `Symbol` kind are compared. Leading it to silently discard the `Constraint`.
This raises two issues:
> 1) This should probably produce an error, rather than silently discarding the `Constraint`
> 2) A better way to produce errors in type families is needed, personally I would love an "error" `Constraint` that takes a `String`/`Symbol` and never holds, producing it's argument `String` as type error (This would remove the need for the hacky unification with `Symbol` to get a somewhat relevant type error).
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Closed TypeFamilies regression","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I first played around with closed typefamilies early 2013 and wrote up the following simple example\r\n\r\n{{{\r\n{-# LANGUAGE ConstraintKinds, DataKinds, PolyKinds, TypeFamilies, TypeOperators #-}\r\n \r\nimport GHC.Prim (Constraint)\r\n \r\ntype family Restrict (a :: k) (as :: [k]) :: Constraint\r\ntype instance where\r\n Restrict a (a ': as) = (a ~ \"Oops! Tried to apply a restricted type!\")\r\n Restrict x (a ': as) = Restrict x as\r\n Restrict x '[] = ()\r\n \r\nfoo :: Restrict a '[(), Int] => a -> a\r\nfoo = id\r\n}}}\r\n\r\nThis worked fine, functioning like `id` for types other than `()` and `Int` and returning a type error for `()` and `Int`.\r\n\r\nAfter hearing comments that my example broke when the closed type families syntax changed I decided to update my version of 7.7 and change the code for that. The new code is:\r\n\r\n{{{\r\n{-# LANGUAGE ConstraintKinds, DataKinds, PolyKinds, TypeFamilies, TypeOperators #-}\r\n \r\nimport GHC.Prim (Constraint)\r\n \r\ntype family Restrict (a :: k) (as :: [k]) :: Constraint where\r\n Restrict a (a ': as) = (a ~ \"Oops! Tried to apply a restricted type!\")\r\n Restrict x (a ': as) = Restrict x as\r\n Restrict x '[] = ()\r\n \r\nfoo :: Restrict a '[(), Int] => a -> a\r\nfoo = id\r\n}}}\r\n\r\nThis code is accepted by the compiler just fine, but the `Constraint` gets thrown out. When querying ghci for the type of `foo` the following is returned:\r\n\r\n{{{\r\nλ :t foo\r\nfoo :: a -> a\r\nλ :i foo\r\nfoo :: (Restrict a '[(), Int]) => a -> a\r\n}}}\r\n\r\nAdditionally, in the recent 7.7 `foo ()` returns `()` rather than a type error. After some playing around this seems to be caused by the \"(a ~ \"Oops! Tried to apply a restricted type!\")\" equality constraint. It seems GHC decides that it doesn't like the fact that types with a polymorphic kind and `Symbol` kind are compared. Leading it to silently discard the `Constraint`.\r\n\r\nThis raises two issues:\r\n 1) This should probably produce an error, rather than silently discarding the `Constraint`\r\n 2) A better way to produce errors in type families is needed, personally I would love an \"error\" `Constraint` that takes a `String`/`Symbol` and never holds, producing it's argument `String` as type error (This would remove the need for the hacky unification with `Symbol` to get a somewhat relevant type error).","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7787modifyMVar does not restore value if callback returns error value2019-07-07T18:48:09ZjoeyadamsmodifyMVar does not restore value if callback returns error value`modifyMVar` is currently implemented as follows:
```
modifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b
modifyMVar m io =
mask $ \restore -> do
a <- takeMVar m
(a',b) <- restore (io a) `onException` putMVar m a
putMVar ...`modifyMVar` is currently implemented as follows:
```
modifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b
modifyMVar m io =
mask $ \restore -> do
a <- takeMVar m
(a',b) <- restore (io a) `onException` putMVar m a
putMVar m a'
return b
```
The problem is that it forces the `(a',b)` outside of the exception handler. If forcing this throws an exception, `putMVar` will not be called, and a subsequent `withMVar` or similar will hang. Example:
```
> import Control.Concurrent.MVar
> mv <- newMVar 'x'
> modifyMVar mv $ \_ -> return undefined
*** Exception: Prelude.undefined
> withMVar mv print
-- hang --
```
Perhaps we can fix it like this:
```
- (a',b) <- restore (io a) `onException` putMVar m a
+ (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"modifyMVar does not restore value if callback returns error value","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"`modifyMVar` is currently implemented as follows:\r\n\r\n{{{\r\nmodifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b\r\nmodifyMVar m io =\r\n mask $ \\restore -> do\r\n a <- takeMVar m\r\n (a',b) <- restore (io a) `onException` putMVar m a\r\n putMVar m a'\r\n return b\r\n}}}\r\n\r\nThe problem is that it forces the `(a',b)` outside of the exception handler. If forcing this throws an exception, `putMVar` will not be called, and a subsequent `withMVar` or similar will hang. Example:\r\n\r\n{{{\r\n> import Control.Concurrent.MVar\r\n> mv <- newMVar 'x'\r\n> modifyMVar mv $ \\_ -> return undefined\r\n*** Exception: Prelude.undefined\r\n> withMVar mv print\r\n-- hang --\r\n}}}\r\n\r\nPerhaps we can fix it like this:\r\n\r\n{{{\r\n- (a',b) <- restore (io a) `onException` putMVar m a\r\n+ (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->7.8.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/7646resource busy (file is locked) with multi-threaded file ops2019-07-07T18:48:51ZStefanWehrresource busy (file is locked) with multi-threaded file opsThe sample program attached creates 10 worker threads, each of which takes a different file name. Each worker thread then writes the file, reads the file, writes the file and so on. File operations use \*strict IO\*.
When compiled witho...The sample program attached creates 10 worker threads, each of which takes a different file name. Each worker thread then writes the file, reads the file, writes the file and so on. File operations use \*strict IO\*.
When compiled without `-threaded` everything is ok, that is, the program goes on forever without any error messages.
But with `-threaded`, the program quickly fails with `ERROR in worker 4: 4: openBinaryFile: resource busy (file is locked)`.
Tested under Mac OSX 10.8.2 and Linux.
Tested with both GHC 7.6.1 and 7.6.2.
I could reproduce the bug without +RTS -N -RTS and with this RTS option. A colleague of mine reports that it needs +RTS -N2 -RTS to reproduce the bug.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.6.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"resource busy (file is locked) with multi-threaded file ops","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The sample program attached creates 10 worker threads, each of which takes a different file name. Each worker thread then writes the file, reads the file, writes the file and so on. File operations use *strict IO*.\r\n\r\nWhen compiled without `-threaded` everything is ok, that is, the program goes on forever without any error messages.\r\n\r\nBut with `-threaded`, the program quickly fails with `ERROR in worker 4: 4: openBinaryFile: resource busy (file is locked)`.\r\n\r\nTested under Mac OSX 10.8.2 and Linux.\r\nTested with both GHC 7.6.1 and 7.6.2.\r\n\r\nI could reproduce the bug without +RTS -N -RTS and with this RTS option. A colleague of mine reports that it needs +RTS -N2 -RTS to reproduce the bug.","type_of_failure":"OtherFailure","blocking":[]} -->7.6.3Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/7325threadDelay mistreats minBound and maxBound in some configurations2019-07-07T18:50:14ZjoeyadamsthreadDelay mistreats minBound and maxBound in some configurationsthreadDelay currently treats minBound and maxBound incorrectly in some cases. This breaks the following idiom ([as seen in the async package](http://hackage.haskell.org/packages/archive/async/latest/doc/html/src/Control-Concurrent-Async....threadDelay currently treats minBound and maxBound incorrectly in some cases. This breaks the following idiom ([as seen in the async package](http://hackage.haskell.org/packages/archive/async/latest/doc/html/src/Control-Concurrent-Async.html#Concurrently)):
```
forever (threadDelay maxBound)
```
On Linux (Ubuntu 10.04 64-bit) without -threaded, `threadDelay maxBound` returns immediately. For lower numbers on the same order of magnitude, it behaves non-deterministically. For example, given this program:
```
import Control.Concurrent
import Control.Monad
main = forM_ [6244222868950683224..] $ \i -> do
print i
threadDelay i
```
threadDelay returns immediately in some cases but not in others. If I compile and run it in bash like this:
```
ghc-7.6.1 -fforce-recomp threadDelay-maxBound.hs ; ./threadDelay-maxBound
```
The bug usually appears, but if I run it like this:
```
ghc-7.6.1 -fforce-recomp threadDelay-maxBound.hs
./threadDelay-maxBound
```
The bug does not appear (threadDelay blocks like it should). Thus, the program is affected by a very subtle difference in how it is invoked. Perhaps it is sensitive to file descriptor numbers.
On Windows without -threaded, `threadDelay maxBound` seems to work, but `threadDelay minBound` blocks rather than returning immediately.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 7.6.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | Unknown/Multiple |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"threadDelay mistreats minBound and maxBound in some configurations","status":"New","operating_system":"Unknown/Multiple","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"threadDelay currently treats minBound and maxBound incorrectly in some cases. This breaks the following idiom ([http://hackage.haskell.org/packages/archive/async/latest/doc/html/src/Control-Concurrent-Async.html#Concurrently as seen in the async package]):\r\n\r\n{{{\r\nforever (threadDelay maxBound)\r\n}}}\r\n\r\nOn Linux (Ubuntu 10.04 64-bit) without -threaded, {{{threadDelay maxBound}}} returns immediately. For lower numbers on the same order of magnitude, it behaves non-deterministically. For example, given this program:\r\n\r\n{{{\r\nimport Control.Concurrent\r\nimport Control.Monad\r\n\r\nmain = forM_ [6244222868950683224..] $ \\i -> do\r\n print i\r\n threadDelay i\r\n}}}\r\n\r\nthreadDelay returns immediately in some cases but not in others. If I compile and run it in bash like this:\r\n\r\n{{{\r\nghc-7.6.1 -fforce-recomp threadDelay-maxBound.hs ; ./threadDelay-maxBound\r\n}}}\r\n\r\nThe bug usually appears, but if I run it like this:\r\n\r\n{{{\r\nghc-7.6.1 -fforce-recomp threadDelay-maxBound.hs\r\n./threadDelay-maxBound\r\n}}}\r\n\r\nThe bug does not appear (threadDelay blocks like it should). Thus, the program is affected by a very subtle difference in how it is invoked. Perhaps it is sensitive to file descriptor numbers.\r\n\r\nOn Windows without -threaded, {{{threadDelay maxBound}}} seems to work, but {{{threadDelay minBound}}} blocks rather than returning immediately.","type_of_failure":"OtherFailure","blocking":[]} -->8.2.1https://gitlab.haskell.org/ghc/ghc/-/issues/7160C finalizers are reversed during GC2019-07-07T18:51:04ZBertram FelgenhauerC finalizers are reversed during GC(See also thread starting at http://www.haskell.org/pipermail/libraries/2012-August/018302.html )
The list of finalizers is reversed during GC (cf. `rts/sm/MarkWeak.c`), which may cause them to run in the wrong order.
The following prog...(See also thread starting at http://www.haskell.org/pipermail/libraries/2012-August/018302.html )
The list of finalizers is reversed during GC (cf. `rts/sm/MarkWeak.c`), which may cause them to run in the wrong order.
The following program reproduces this behaviour.
```
{-# LANGUAGE ForeignFunctionInterface, MagicHash #-}
import GHC.ForeignPtr
import GHC.Ptr
import System.Mem
-- one should really use own C function rather than this varargs one to avoid
-- possible ABI issues
foreign import ccall "&debugBelch" fun :: FunPtr (Ptr () -> Ptr () -> IO ())
new name = do
p <- newForeignPtr_ (Ptr name)
addForeignPtrFinalizerEnv fun (Ptr "finalizer 1 (%s)\n"#) p
addForeignPtrFinalizerEnv fun (Ptr "finalizer 2 (%s)\n"#) p
return p
main = do
p <- new "p"#
q <- new "q"#
r <- new "r"#
performGC -- collect p. finalizer order: 2, then 1.
print q
performGC -- collect q. finalizer order: 1, then 2.
-- expected order: 2, then 1.
print r
performGC -- collect r. finalizer order: 2, then 1.
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.6.1-rc1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"C finalizers are reversed during GC","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.1-rc1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"(See also thread starting at http://www.haskell.org/pipermail/libraries/2012-August/018302.html )\r\n\r\nThe list of finalizers is reversed during GC (cf. {{{rts/sm/MarkWeak.c}}}), which may cause them to run in the wrong order.\r\nThe following program reproduces this behaviour.\r\n\r\n{{{\r\n{-# LANGUAGE ForeignFunctionInterface, MagicHash #-}\r\nimport GHC.ForeignPtr\r\nimport GHC.Ptr\r\nimport System.Mem\r\n\r\n-- one should really use own C function rather than this varargs one to avoid\r\n-- possible ABI issues\r\nforeign import ccall \"&debugBelch\" fun :: FunPtr (Ptr () -> Ptr () -> IO ())\r\n\r\nnew name = do\r\n p <- newForeignPtr_ (Ptr name)\r\n addForeignPtrFinalizerEnv fun (Ptr \"finalizer 1 (%s)\\n\"#) p\r\n addForeignPtrFinalizerEnv fun (Ptr \"finalizer 2 (%s)\\n\"#) p\r\n return p\r\n\r\nmain = do\r\n p <- new \"p\"#\r\n q <- new \"q\"#\r\n r <- new \"r\"#\r\n performGC -- collect p. finalizer order: 2, then 1.\r\n print q\r\n performGC -- collect q. finalizer order: 1, then 2.\r\n -- expected order: 2, then 1.\r\n print r\r\n performGC -- collect r. finalizer order: 2, then 1.\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/6156Optimiser bug on linux-powerpc2019-07-07T18:51:54ZerikdOptimiser bug on linux-powerpcFound a small chunk of code in the cryptocipher package that when compiled and run, produces a difference result when optimised compared to compiling un-optimised.
Note this is only a problem with PowerPC. On x86-64 there is no differen...Found a small chunk of code in the cryptocipher package that when compiled and run, produces a difference result when optimised compared to compiling un-optimised.
Note this is only a problem with PowerPC. On x86-64 there is no difference in the output between the optimised version and the un-optimised version.
I have two simple files (Camellia.hs):
```
module Camellia where
import Data.Bits
import Data.Word
import Debug.Trace
fl :: Word64 -> Word64 -> Word64
fl fin sk =
let (x1, x2) = w64tow32 fin in
let (k1, k2) = w64tow32 sk in
let y2 = x2 `xor` ((x1 .&. k1) `rotateL` 1) in
let y1 = x1 `xor` (y2 .|. k2) in
trace (show fin ++ " " ++ show sk ++ " -> " ++ show (w32tow64 (y1, y2))) $ w32tow64 (y1, y2)
w64tow32 :: Word64 -> (Word32, Word32)
w64tow32 w = (fromIntegral (w `shiftR` 32), fromIntegral (w .&. 0xffffffff))
w32tow64 :: (Word32, Word32) -> Word64
w32tow64 (x1, x2) = ((fromIntegral x1) `shiftL` 32) .|. (fromIntegral x2)
```
and a main program (camellia-test.hs):
```
import Data.Word
import qualified Camellia as Camellia
a, b :: Word64
a = 1238988323332265734
b = 11185553392205053542
main :: IO ()
main =
putStrLn $ "Camellia.fl " ++ show a ++ " " ++ show b ++ " -> " ++ show (Camellia.fl a b)
```
I'm also using this Makefile:
```
TARGETS = camilla-test-std camilla-test-opt
check : $(TARGETS)
./camilla-test-std
./camilla-test-opt
clean :
make clean-temp-files
rm -f $(TARGETS)
clean-temp-files :
rm -f camilla-test.o camilla-test.hi Camellia.o Camellia.hi
camilla-test-opt : camilla-test.hs Camellia.hs
ghc -Wall -O2 --make -i:Tests $< -o $@
make clean-temp-files
camilla-test-std : camilla-test.hs Camellia.hs
ghc -Wall --make -i:Tests $< -o $@
make clean-temp-files
```
When I run the two programs I get:
```
./camilla-test-std
1238988323332265734 11185553392205053542 -> 18360184157246690566
Camellia.fl 1238988323332265734 11185553392205053542 -> 18360184157246690566
./camilla-test-opt
1238988323332265734 11185553392205053542 -> 3698434091925017862
Camellia.fl 38662 15974 -> 3698434091925017862
```
So there are two problems here:
a) Showing Word64 values is not working correctly in the optimised version.
b) The function Camelia.fl produces the wrong result in the optimised version.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.4.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Optimiser bug on linux-powerpc","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Found a small chunk of code in the cryptocipher package that when compiled and run, produces a difference result when optimised compared to compiling un-optimised.\r\n\r\nNote this is only a problem with PowerPC. On x86-64 there is no difference in the output between the optimised version and the un-optimised version.\r\n\r\nI have two simple files (Camellia.hs):\r\n\r\n{{{\r\nmodule Camellia where\r\n\r\nimport Data.Bits\r\nimport Data.Word\r\n\r\nimport Debug.Trace\r\n\r\nfl :: Word64 -> Word64 -> Word64\r\nfl fin sk =\r\n\tlet (x1, x2) = w64tow32 fin in\r\n\tlet (k1, k2) = w64tow32 sk in\r\n\tlet y2 = x2 `xor` ((x1 .&. k1) `rotateL` 1) in\r\n\tlet y1 = x1 `xor` (y2 .|. k2) in\r\n\ttrace (show fin ++ \" \" ++ show sk ++ \" -> \" ++ show (w32tow64 (y1, y2))) $ w32tow64 (y1, y2)\r\n\r\nw64tow32 :: Word64 -> (Word32, Word32)\r\nw64tow32 w = (fromIntegral (w `shiftR` 32), fromIntegral (w .&. 0xffffffff))\r\n\r\nw32tow64 :: (Word32, Word32) -> Word64\r\nw32tow64 (x1, x2) = ((fromIntegral x1) `shiftL` 32) .|. (fromIntegral x2)\r\n}}}\r\n\r\nand a main program (camellia-test.hs):\r\n\r\n{{{\r\n\r\nimport Data.Word\r\nimport qualified Camellia as Camellia\r\n\r\na, b :: Word64\r\na = 1238988323332265734\r\nb = 11185553392205053542\r\n\r\nmain :: IO ()\r\nmain =\r\n putStrLn $ \"Camellia.fl \" ++ show a ++ \" \" ++ show b ++ \" -> \" ++ show (Camellia.fl a b)\r\n\r\n}}}\r\n\r\nI'm also using this Makefile:\r\n\r\n{{{\r\nTARGETS = camilla-test-std camilla-test-opt\r\n\r\ncheck : $(TARGETS)\r\n\t./camilla-test-std\r\n\t./camilla-test-opt\r\n\r\nclean :\r\n\tmake clean-temp-files\r\n\trm -f $(TARGETS)\r\n\r\nclean-temp-files :\r\n\trm -f camilla-test.o camilla-test.hi Camellia.o Camellia.hi\r\n\r\ncamilla-test-opt : camilla-test.hs Camellia.hs\r\n\tghc -Wall -O2 --make -i:Tests $< -o $@\r\n\tmake clean-temp-files\r\n\r\ncamilla-test-std : camilla-test.hs Camellia.hs\r\n\tghc -Wall --make -i:Tests $< -o $@\r\n\tmake clean-temp-files\r\n}}}\r\n\r\nWhen I run the two programs I get:\r\n\r\n{{{\r\n./camilla-test-std\r\n1238988323332265734 11185553392205053542 -> 18360184157246690566\r\nCamellia.fl 1238988323332265734 11185553392205053542 -> 18360184157246690566\r\n./camilla-test-opt\r\n1238988323332265734 11185553392205053542 -> 3698434091925017862\r\nCamellia.fl 38662 15974 -> 3698434091925017862\r\n}}}\r\n\r\nSo there are two problems here:\r\n\r\na) Showing Word64 values is not working correctly in the optimised version.\r\n\r\nb) The function Camelia.fl produces the wrong result in the optimised version.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/6131-fprof-auto adds cost centers to INLINE functions2019-07-07T18:52:01Ztakano-akio-fprof-auto adds cost centers to INLINE functionsAccording to the Section 5.2 of User's Guide, -fprof-auto should add cost centers only to functions that are not marked INLINE. However GHC 7.4 doesn't respect this.
A simple example:
```
foo :: Integer -> Integer
foo x = x + 100
{-# I...According to the Section 5.2 of User's Guide, -fprof-auto should add cost centers only to functions that are not marked INLINE. However GHC 7.4 doesn't respect this.
A simple example:
```
foo :: Integer -> Integer
foo x = x + 100
{-# INLINE foo #-}
main = print $ loop (10000000::Int) 10000000000000000000000
where
loop 0 x = x
loop n x = loop (n-1) (foo x)
```
Compile and run this like:
```
% ghc -prof -fprof-auto -O2 test.hs
% ./test +RTS -p
% grep foo test.prof
```
And you will see 'foo' is listed as a cost center.
This happens with GHC 7.4.1 and 7.4.2-rc1
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.4.2-rc1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"-fprof-auto adds cost centers to INLINE functions","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.2-rc1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"According to the Section 5.2 of User's Guide, -fprof-auto should add cost centers only to functions that are not marked INLINE. However GHC 7.4 doesn't respect this.\r\n\r\nA simple example:\r\n\r\n{{{\r\nfoo :: Integer -> Integer\r\nfoo x = x + 100\r\n{-# INLINE foo #-}\r\n\r\nmain = print $ loop (10000000::Int) 10000000000000000000000\r\n where\r\n loop 0 x = x\r\n loop n x = loop (n-1) (foo x)\r\n}}}\r\n\r\nCompile and run this like:\r\n\r\n{{{\r\n% ghc -prof -fprof-auto -O2 test.hs\r\n% ./test +RTS -p\r\n% grep foo test.prof\r\n}}}\r\n\r\nAnd you will see 'foo' is listed as a cost center.\r\n\r\nThis happens with GHC 7.4.1 and 7.4.2-rc1","type_of_failure":"OtherFailure","blocking":[]} -->7.4.3https://gitlab.haskell.org/ghc/ghc/-/issues/6116ctrl-c doesn't always work when entering text in ghci2019-07-07T18:52:06Zjudahjctrl-c doesn't always work when entering text in ghciWith ghci-7.5.20120519 (on Mac and probably also Linux): type some text, then press ctrl-c. Then type more text, and press ctrl-c again. The first time you press ctrl-c, it starts a new line. But the second time you press ctrl-c, nothing...With ghci-7.5.20120519 (on Mac and probably also Linux): type some text, then press ctrl-c. Then type more text, and press ctrl-c again. The first time you press ctrl-c, it starts a new line. But the second time you press ctrl-c, nothing happens. (Actually running code from within ghci resets this process.)
This is a regression from the behavior of ghci-7.4.1, where every time you press ctrl-C it caused a new line to be printed.
From my initial investigation, I think this was caused by ghc commit 206c8fc3ebd64c40ae09742fdea09ffd0f915d5c, which was used to fix #2786.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.5 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"ctrl-c doesn't always work when entering text in ghci","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.5","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"With ghci-7.5.20120519 (on Mac and probably also Linux): type some text, then press ctrl-c. Then type more text, and press ctrl-c again. The first time you press ctrl-c, it starts a new line. But the second time you press ctrl-c, nothing happens. (Actually running code from within ghci resets this process.)\r\n\r\nThis is a regression from the behavior of ghci-7.4.1, where every time you press ctrl-C it caused a new line to be printed.\r\n\r\nFrom my initial investigation, I think this was caused by ghc commit 206c8fc3ebd64c40ae09742fdea09ffd0f915d5c, which was used to fix #2786. ","type_of_failure":"OtherFailure","blocking":[]} -->7.6.1https://gitlab.haskell.org/ghc/ghc/-/issues/5870writeChan is not 100% exception-safe2019-07-07T18:53:11ZjoeyadamswriteChan is not 100% exception-safeControl.Concurrent.Chan.writeChan is currently implemented like this:
```
writeChan :: Chan a -> a -> IO ()
writeChan (Chan _ writeVar) val = do
new_hole <- newEmptyMVar
modifyMVar_ writeVar $ \old_hole -> do
putMVar old_hole (C...Control.Concurrent.Chan.writeChan is currently implemented like this:
```
writeChan :: Chan a -> a -> IO ()
writeChan (Chan _ writeVar) val = do
new_hole <- newEmptyMVar
modifyMVar_ writeVar $ \old_hole -> do
putMVar old_hole (ChItem val new_hole)
return new_hole
```
The problem is that modifyMVar_ restores the exception mask when it calls the callback. If an asynchronous exception is delivered immediately after the putMVar, the Chan's write end will be set to a filled hole, violating a key invariant.
I think it should be implemented like this:
```
writeChan :: Chan a -> a -> IO ()
writeChan (Chan _ writeVar) val = do
new_hole <- newEmptyMVar
mask_ $ do
old_hole <- takeMVar writeVar -- (1)
putMVar old_hole (ChItem val new_hole) -- (2)
putMVar writeVar new_hole -- (3)
```
This looks a bit naïve, but it should be atomic, at least in theory:
- (1) is interruptible. However, if it is interrupted, the MVar will remain intact.
- (2) is not interruptible, because old_hole is guaranteed to be empty. No other thread can fill it because we have taken exclusive access to writeVar.
- (3) is not interruptible, because we have taken exclusive access to writeVar.
This implementation has the added benefit of removing an exception handler, which should make it slightly faster.
readChan is okay, though:
```
readChan :: Chan a -> IO a
readChan (Chan readVar _) = do
modifyMVar readVar $ \read_end -> do
(ChItem val new_read_end) <- readMVar read_end
return (new_read_end, val)
```
If an exception is received immediately after the readMVar, then the read cursor will not be advanced, and the next call to readChan will simply read from that position again. Unfortunately, we can't get rid of the exception handler like we did with writeChan, because `readMVar read_end` is interruptible.
The attached patch changes the implementation of writeChan to the one shown above, and adds a comment to the definition of Chan about the write end's empty-hole invariant. I believe all of the Chan operations preserve this invariant, even the deprecated unGetChan and isEmptyChan.
I have not been able to create a test case where writeChan is interrupted between filling the hole and updating the write cursor. Perhaps it doesn't actually happen in practice, or perhaps it is extremely rare. But by my understanding of the semantics:
```
mask $ \restore -> do
thing1
restore $ putMVar ...
thing2
```
It is possible for an exception to arrive after the putMVar and before thing2.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/base |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"writeChan is not 100% exception-safe","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Control.Concurrent.Chan.writeChan is currently implemented like this:\r\n\r\n{{{\r\nwriteChan :: Chan a -> a -> IO ()\r\nwriteChan (Chan _ writeVar) val = do\r\n new_hole <- newEmptyMVar\r\n modifyMVar_ writeVar $ \\old_hole -> do\r\n putMVar old_hole (ChItem val new_hole)\r\n return new_hole\r\n}}}\r\n\r\nThe problem is that modifyMVar_ restores the exception mask when it calls the callback. If an asynchronous exception is delivered immediately after the putMVar, the Chan's write end will be set to a filled hole, violating a key invariant.\r\n\r\nI think it should be implemented like this:\r\n\r\n{{{\r\nwriteChan :: Chan a -> a -> IO ()\r\nwriteChan (Chan _ writeVar) val = do\r\n new_hole <- newEmptyMVar\r\n mask_ $ do\r\n old_hole <- takeMVar writeVar -- (1)\r\n putMVar old_hole (ChItem val new_hole) -- (2)\r\n putMVar writeVar new_hole -- (3)\r\n}}}\r\n\r\nThis looks a bit naïve, but it should be atomic, at least in theory:\r\n\r\n * (1) is interruptible. However, if it is interrupted, the MVar will remain intact.\r\n\r\n * (2) is not interruptible, because old_hole is guaranteed to be empty. No other thread can fill it because we have taken exclusive access to writeVar.\r\n\r\n * (3) is not interruptible, because we have taken exclusive access to writeVar.\r\n\r\nThis implementation has the added benefit of removing an exception handler, which should make it slightly faster.\r\n\r\nreadChan is okay, though:\r\n\r\n{{{\r\nreadChan :: Chan a -> IO a\r\nreadChan (Chan readVar _) = do\r\n modifyMVar readVar $ \\read_end -> do\r\n (ChItem val new_read_end) <- readMVar read_end\r\n return (new_read_end, val)\r\n}}}\r\n\r\nIf an exception is received immediately after the readMVar, then the read cursor will not be advanced, and the next call to readChan will simply read from that position again. Unfortunately, we can't get rid of the exception handler like we did with writeChan, because {{{readMVar read_end}}} is interruptible.\r\n\r\nThe attached patch changes the implementation of writeChan to the one shown above, and adds a comment to the definition of Chan about the write end's empty-hole invariant. I believe all of the Chan operations preserve this invariant, even the deprecated unGetChan and isEmptyChan.\r\n\r\nI have not been able to create a test case where writeChan is interrupted between filling the hole and updating the write cursor. Perhaps it doesn't actually happen in practice, or perhaps it is extremely rare. But by my understanding of the semantics:\r\n\r\n{{{\r\nmask $ \\restore -> do\r\n thing1\r\n restore $ putMVar ...\r\n thing2\r\n}}}\r\n\r\nIt is possible for an exception to arrive after the putMVar and before thing2.","type_of_failure":"OtherFailure","blocking":[]} -->7.4.2Simon MarlowSimon Marlow