GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2024-03-23T22:14:54Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/24507Unsound optimization breaks pattern matching on sum type2024-03-23T22:14:54ZStefano DebenedettiUnsound optimization breaks pattern matching on sum type## Summary
Enabling `-O2` makes a case expression pattern match pick the 7th constructor of a sum type also when called with any constructor from the 2nd to the 6th.
The following factors seem to concur in triggering this behaviour (se...## Summary
Enabling `-O2` makes a case expression pattern match pick the 7th constructor of a sum type also when called with any constructor from the 2nd to the 6th.
The following factors seem to concur in triggering this behaviour (see the Expected behaviour section below for more details):
* `-O2`
* usage of the `streamly-core` library (I could not reproduce without it)
* a strictness annotation on the type used to hold the constructor to pass to the buggy function
* splitting the code into separate modules
On the other hand, using `Debug.Trace.trace` to examine the constructor before feeding it into the case expression fixes the issue, making it a Heisenbug.
## Steps to reproduce
```
$ git clone https://github.com/demaledetti/test-bug
$ cd test-bug
$ cabal clean && cabal build --ghc-options -v > cabal.log.ko 2>&1 && for i in {A..J}; do cabal run testbug -- $i; done
parser: A
testbug: src/TestBug/Parser.hs:(15,18)-(25,34): Non-exhaustive patterns in case
parser: B
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: C
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: D
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: E
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: F
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: G
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: H
OK
parser: I
OK
parser: J
testbug: src/TestBug/Parser.hs:(15,18)-(25,34): Non-exhaustive patterns in case
```
## Expected behaviour
With `-O1`:
```
$ cabal clean && cabal build -O1 --ghc-options -v > cabal.log.ok 2>&1 && for i in {A..J}; do cabal run -O1 testbug -- $i; done
parser: A
testbug: src/TestBug/Parser.hs:(15,18)-(25,34): Non-exhaustive patterns in case
parser: B
OK
parser: C
OK
parser: D
OK
parser: E
OK
parser: F
OK
parser: G
testbug: Prelude.undefined
CallStack (from HasCallStack):
undefined, called at src/TestBug/Parser.hs:23:10 in test-bug-0.1.0.0-inplace:TestBug.Parser
parser: H
OK
parser: I
OK
parser: J
testbug: src/TestBug/Parser.hs:(15,18)-(25,34): Non-exhaustive patterns in case
```
For other ways to get the correct behaviour without lowering the optimization level, including the ones mentioned in the Summary section above, see these comments in the source code:
```
$ grep -rnI "the bug" src/ testbug/
src/TestBug/Data.hs:12: -- simplifying it away makes the bug disappear
src/TestBug/Parser.hs:5:-- makes the bug go away (making it a Heisenbug)
src/TestBug/Parser.hs:16: -- uncommenting the next line makes the bug disappear
src/TestBug/Parser.hs:26: -- uncommenting the next line makes the bug disappear
testbug/Main.hs:13:-- makes the bug go away
```
## Environment
* GHC version used: 9.8.2
Optional:
* Operating System:
* System Architecture:
```
$ uname -a
Linux eppere 6.7.5-gentoo #1 SMP Mon Feb 19 15:51:31 CET 2024 x86_64 Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz GenuineIntel GNU/Linux
```
Logs mentioned above:
[cabal.log.ko](/uploads/5c86dcaaac0efe1a297a3534d2e6b3a4/cabal.log.ko)
[cabal.log.ok](/uploads/aa5c0a45405cbf6e9fad05b1219dcd07/cabal.log.ok)
Log of build with `-O2` but removing the strictness annotation in `Main.hs` (commenting line 14, uncommenting line 15):
[cabal.log.lazy](/uploads/b63f0ae3c422538bb04ed7b623c49c50/cabal.log.lazy)
(easier to diff vs cabal.log.ko)9.8.3Andreas KlebingerAndreas Klebingerhttps://gitlab.haskell.org/ghc/ghc/-/issues/21336File flush failures during program deinitialization aren't indicated2024-03-21T17:37:33ZBrandon S. Allberyallbery.b@gmail.comFile flush failures during program deinitialization aren't indicated## Summary
If a flush/close of a `Handle` fails during RTS deinitialization, there is no indication of a failure. Even if `stderr` has already been closed, at minimum the exit status can be set to indicate a failure.
## Steps to reprod...## Summary
If a flush/close of a `Handle` fails during RTS deinitialization, there is no indication of a failure. Even if `stderr` has already been closed, at minimum the exit status can be set to indicate a failure.
## Steps to reproduce
The program
```
main = putStrLn "Hello, world!"
```
invoked as
```
./hello >/dev/full
```
will correctly report
```
<stdout>: commitBuffer: resource exhausted (No space left on device)
```
if run from `ghci` or `runghc`, which default `stdout` to `LineBuffering`. In a compiled program, `stdout` is set to `BlockBuffering Nothing` and the final `hFlush` is done by the RTS at a time when no exceptions can be thrown and `stderr` may already be closed, so nothing is reported and the program exits with status 0 (no error).
I suspect the same thing may happen with a `Handle` that is garbage collected, since it may be unsafe to throw an exception at that point.
## Expected behavior
Preferably report the same exception as with `ghci` or `runghc`, but at minimum report a non-zero exit status.
## Environment
* GHC version used: 8.10.7 and 9.2.1
Optional:
* Operating System: Linux (Ubuntu 20.04)
* System Architecture: x86_64https://gitlab.haskell.org/ghc/ghc/-/issues/10542Incorrect Unicode input on Windows Console2024-03-14T23:23:51ZptroevIncorrect Unicode input on Windows ConsoleTo reproduce:
- start a windows console
- change the console's font to a ttf unicode font, like "Lucida Console".
- type "chcp 65001" to set it to the UTF-8 code page.
- start ghci (same error appears when running compiled executable)
- ...To reproduce:
- start a windows console
- change the console's font to a ttf unicode font, like "Lucida Console".
- type "chcp 65001" to set it to the UTF-8 code page.
- start ghci (same error appears when running compiled executable)
- \> import System.IO (or GHC.IO.Handle)
- \> enc \<- mkTextEncoding "UTF8"
- \> hSetEncoding stdin enc
- \> getLine
- \> Фывфыв (or any international unicode sequence)
- \*\* Exception: \<stdin\>: hGetLine: end of file
<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 | #4471 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Incorrect Unicode input on Windows Console","status":"New","operating_system":"","component":"Compiler","related":[4471],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":["65001","chcp","cmd","getLine","stdin","utf-8","windows"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"To reproduce:\r\n- start a windows console\r\n- change the console's font to a ttf unicode font, like \"Lucida Console\".\r\n- type \"chcp 65001\" to set it to the UTF-8 code page.\r\n- start ghci (same error appears when running compiled executable)\r\n- > import System.IO (or GHC.IO.Handle)\r\n- > enc <- mkTextEncoding \"UTF8\"\r\n- > hSetEncoding stdin enc\r\n- > getLine\r\n- > Фывфыв (or any international unicode sequence)\r\n*** Exception: <stdin>: hGetLine: end of file\r\n","type_of_failure":"OtherFailure","blocking":[]} -->Tamar ChristinaTamar Christinahttps://gitlab.haskell.org/ghc/ghc/-/issues/24515Many profiling tests broken on Windows2024-03-09T14:39:42ZBen GamariMany profiling tests broken on WindowsIn the 9.10.1-alpha1 release job I found that many profiling-related tests are broken on Windows (see https://gitlab.haskell.org/ghc/ghc/-/jobs/1800492, https://gitlab.haskell.org/ghc/ghc/-/jobs/1800548):
```
Unexpected failures:
C:/G...In the 9.10.1-alpha1 release job I found that many profiling-related tests are broken on Windows (see https://gitlab.haskell.org/ghc/ghc/-/jobs/1800492, https://gitlab.haskell.org/ghc/ghc/-/jobs/1800548):
```
Unexpected failures:
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc1.run CallerCc1 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc1.run CallerCc1 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc2.run CallerCc2 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc2.run CallerCc2 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc3.run CallerCc3 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/caller-cc/CallerCc3.run CallerCc3 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/ignore_scc.run ignore_scc [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/ignore_scc.run ignore_scc [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/ioprof.run ioprof [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/ioprof.run ioprof [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/prof-doc-fib.run prof-doc-fib [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/prof-doc-fib.run prof-doc-fib [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/prof-doc-last.run prof-doc-last [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/prof-doc-last.run prof-doc-last [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/profinline001.run profinline001 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/profinline001.run profinline001 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded-calls001.run scc-prof-overloaded-calls001 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded-calls001.run scc-prof-overloaded-calls001 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded-calls002.run scc-prof-overloaded-calls002 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded-calls002.run scc-prof-overloaded-calls002 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded001.run scc-prof-overloaded001 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded001.run scc-prof-overloaded001 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded002.run scc-prof-overloaded002 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc-prof-overloaded002.run scc-prof-overloaded002 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc001.run scc001 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc002.run scc002 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc002.run scc002 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc003.run scc003 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc003.run scc003 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc005.run scc005 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/scc005.run scc005 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T12962.run T12962 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T12962.run T12962 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T2552.run T2552 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T2552.run T2552 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T5654-O0.run T5654-O0 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T5654-O1.run T5654-O1 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T5654b-O0.run T5654b-O0 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T5654b-O1.run T5654b-O1 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T680.run T680 [bad profile] (prof)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/T680.run T680 [bad profile] (profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/toplevel_scc_1.run toplevel_scc_1 [bad profile] (prof_no_auto)
```
It appears that the profile wasn't created in most of these cases, failing with output of the form:
```
*** unexpected failure for profinline001(profasm)
C:/GitLabRunner/builds/0/1800548/tmp/ghctest-m0rwyh7h/test spaces/testsuite/tests/profiling/should_run/profinline001.run/profinline001.exe.prof does not exist
```Ben GamariBen Gamarihttps://gitlab.haskell.org/ghc/ghc/-/issues/23003Programs loop forever when run with --nonmoving-gc on Windows using GHC 9.4.4+2024-02-15T19:03:59ZRyan ScottPrograms loop forever when run with --nonmoving-gc on Windows using GHC 9.4.4+Given the following program:
```hs
module Main where
main :: IO ()
main = putStrLn "Hello, World!"
```
If you compile this with GHC 9.4.4 or GHC 9.6.1-alpha3, you will be able to run it with the default RTS options:
```
$ ghc-9.4.4 M...Given the following program:
```hs
module Main where
main :: IO ()
main = putStrLn "Hello, World!"
```
If you compile this with GHC 9.4.4 or GHC 9.6.1-alpha3, you will be able to run it with the default RTS options:
```
$ ghc-9.4.4 Main.hs
[1 of 2] Compiling Main ( Main.hs, Main.o )
[2 of 2] Linking Main.exe
$ ./Main.exe
Hello, World!
```
If you try to run it with the `--nonmoving-gc` RTS option, however, then the program will loop forever:
```
$ ./Main.exe +RTS --nonmoving-gc -RTS
Hello, World!
# The program hangs at this point, and Ctrl-C is not enough to kill it.
# The program must be manually killed with the Task Manager.
```
In larger applications, this bug has likely been responsible for access violations instead of infinite loops (see [here](https://github.com/haskell/filepath/pull/181#issuecomment-1435732101) for an example).
This is a regression from GHC 9.2.6, which does not exhibit this issue:
```
$ ghc-9.2.6 Main.hs
[1 of 1] Compiling Main ( Main.hs, Main.o )
Linking Main.exe ...
$ ./Main.exe +RTS --nonmoving-gc -RTS
Hello, World!
$ ./Main.exe
Hello, World!
```9.10.1Ben GamariBen Gamarihttps://gitlab.haskell.org/ghc/ghc/-/issues/24295loopification non-sense around void args2024-02-08T17:32:06ZMatthew Cravenclyring@gmail.comloopification non-sense around void args## Summary
`Note [Void arguments in self-recursive tail calls]` looks extremely suspicious. I reproduce it here:
```
-- Note [Void arguments in self-recursive tail calls]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- Stat...## Summary
`Note [Void arguments in self-recursive tail calls]` looks extremely suspicious. I reproduce it here:
```
-- Note [Void arguments in self-recursive tail calls]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- State# tokens can get in the way of the loopification optimization as seen in
-- #11372. Consider this:
--
-- foo :: [a]
-- -> (a -> State# s -> (# State s, Bool #))
-- -> State# s
-- -> (# State# s, Maybe a #)
-- foo [] f s = (# s, Nothing #)
-- foo (x:xs) f s = case f x s of
-- (# s', b #) -> case b of
-- True -> (# s', Just x #)
-- False -> foo xs f s'
--
-- We would like to compile the call to foo as a local jump instead of a call
-- (see Note [Self-recursive tail calls]). However, the generated function has
-- an arity of 2 while we apply it to 3 arguments, one of them being of void
-- type. Thus, we mustn't count arguments of void type when checking whether
-- we can turn a call into a self-recursive jump.
--
```
Nowadays it's very clear that `foo` has a post-unarise arity of 3, and we call it with 3 arguments (one of which happens to be void). And indeed if `foo` tail-called itself with only two arguments (and no final void argument) it would be _utterly wrong_ to just jump to its body. (Of course, this sort of call is only type-correct in the presence of strange recursive newtypes.)
Here's a short program that demonstrates that we can in fact generate such bogus self-jumps today:
<details>
```haskell
module Main (main) where
import Data.IORef (newIORef, readIORef, writeIORef)
import Control.Exception (evaluate)
import GHC.Exts (noinline)
newtype Tricky = TrickyCon { unTrickyCon :: IO Tricky }
main :: IO ()
main = do
ref <- newIORef False
let
tricky :: Tricky
tricky = TrickyCon $ do
putStrLn "tricky call"
v <- readIORef ref
case v of
False -> writeIORef ref True >> evaluate (noinline tricky)
True -> putStrLn "this shouldn't be printed" >> pure tricky
() <$ unTrickyCon tricky
```
</details>
(Why does this reproducer uses the special handling of `evaluate`/`seq#` instead of a direct function call? ...as a work-around for other bugs. Ticket to follow...)
Compile with optimizations and run. The expected output is a single line "tricky call"; the actual output is as follows:
```
tricky call
tricky call
this shouldn't be printed
```
## Environment
* GHC version used: 9.8.1Matthew Cravenclyring@gmail.comMatthew Cravenclyring@gmail.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/24296Simplifier wrongly discards erroring function call2024-02-05T17:53:14ZMatthew Cravenclyring@gmail.comSimplifier wrongly discards erroring function call## Steps to reproduce
Compile with optimisations and run the following module:
```haskell
{-# LANGUAGE GHC2021, UnboxedTuples #-}
module Main (main) where
newtype Tricky = TrickyCon { unTrickyCon :: (# #) -> Tricky }
main :: IO ()
ma...## Steps to reproduce
Compile with optimisations and run the following module:
```haskell
{-# LANGUAGE GHC2021, UnboxedTuples #-}
module Main (main) where
newtype Tricky = TrickyCon { unTrickyCon :: (# #) -> Tricky }
main :: IO ()
main = do
let
tricky :: Tricky
{-# OPAQUE tricky #-}
tricky = TrickyCon $ \(# #) -> TrickyCon $ \(# #) ->
error "tricky called with at least two args"
applyToN :: Int -> Tricky -> Tricky
{-# OPAQUE applyToN #-}
applyToN n a | n == 0 = a
| otherwise = applyToN (n - 1) a `unTrickyCon` (# #)
case applyToN 12345 tricky of
!_ -> putStrLn "unreachable"
```
The function `tricky` is applied to far more than two args, so the error call in its body should be reached. But when run, the program prints "unreachable" and exits successfully instead of failing with "tricky called with at least two args". (This wrong behavior persists even with `-O -fpedantic-bottoms -fno-state-hack`.)
Inspecting the `-ddump-simpl` and `-dverbose-core2core` output suggests the simplifier is eliminating the `applyToN` stuff entirely.
## Environment
* GHC version used: 9.8.1Sebastian GrafSebastian Grafhttps://gitlab.haskell.org/ghc/ghc/-/issues/5859unsafeInterleaveIO duplicates computation when evaluated by multiple threads2024-01-16T02:53:33ZjoeyadamsunsafeInterleaveIO duplicates computation when evaluated by multiple threadsWhen the following code is compiled with -O1 or -O2, the interleaved computation (putStrLn "eval") is performed 1000 times, rather than once:
```
import Control.Concurrent
import Control.Exception (evaluate)
import Control.Monad
import ...When the following code is compiled with -O1 or -O2, the interleaved computation (putStrLn "eval") is performed 1000 times, rather than once:
```
import Control.Concurrent
import Control.Exception (evaluate)
import Control.Monad
import System.IO.Unsafe
main :: IO ()
main = do
x <- unsafeInterleaveIO $ putStrLn "eval"
replicateM_ 1000 $ forkIO $ evaluate x >> return ()
threadDelay 1000000
```
Taking a look at the source to unsafeInterleaveIO:
```
{-# INLINE unsafeInterleaveIO #-}
unsafeInterleaveIO :: IO a -> IO a
unsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)
-- We believe that INLINE on unsafeInterleaveIO is safe, because the
-- state from this IO thread is passed explicitly to the interleaved
-- IO, so it cannot be floated out and shared.
```
It seems the comment about INLINE is not true. If I define the following function:
```
interleave :: IO a -> IO a
interleave = unsafeInterleaveIO
{-# NOINLINE interleave #-}
```
and replace unsafeInterleaveIO with interleave, "eval" is printed only once. If I change NOINLINE to INLINE, or if I remove the pragma altogether, "eval" is printed 1000 times.
I believe unsafeInterleaveIO should *guarantee* that computations are not repeated. Otherwise, we end up with strangeness like this:
```
import Control.Applicative
import Control.Concurrent
import Control.Monad
main :: IO ()
main = do
chan <- newChan :: IO (Chan Int)
mapM_ (writeChan chan) [0..999]
items <- take 10 <$> getChanContents chan
replicateM_ 5 $ forkIO $ putStrLn $ "items = " ++ show items
threadDelay 1000000
```
which prints:
```
items = [0,1,2,3,4,5,6,7,8,9]
items = [10,11,12,13,14,15,16,17,18,19]
items = [20,21,22,23,24,25,26,27,28,29]
items = [30,31,32,33,34,35,36,37,38,39]
items = [40,41,42,43,44,45,46,47,48,49]
```
For the time being, programs can work around this by using a NOINLINE wrapper:
```
getChanContents' :: Chan a -> IO [a]
getChanContents' = getChanContents
{-# NOINLINE getChanContents' #-}
```
I tested this on Linux 64-bit with GHC 7.2.2 and ghc-7.4.0.20120111, and on Windows 32-bit with GHC 7.0.3 and 7.2.2. All of these platforms and versions exhibit the same behavior. The bug goes away when the program is compiled with -O0, or when functions returning interleaved computations are marked NOINLINE (e.g. getChanContents').
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.2.2 |
| 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":"unsafeInterleaveIO duplicates computation when evaluated by multiple threads","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.2.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"When the following code is compiled with -O1 or -O2, the interleaved computation (putStrLn \"eval\") is performed 1000 times, rather than once:\r\n\r\n{{{\r\nimport Control.Concurrent\r\nimport Control.Exception (evaluate)\r\nimport Control.Monad\r\nimport System.IO.Unsafe\r\n\r\nmain :: IO ()\r\nmain = do\r\n x <- unsafeInterleaveIO $ putStrLn \"eval\"\r\n replicateM_ 1000 $ forkIO $ evaluate x >> return ()\r\n threadDelay 1000000\r\n}}}\r\n\r\nTaking a look at the source to unsafeInterleaveIO:\r\n\r\n{{{\r\n{-# INLINE unsafeInterleaveIO #-}\r\nunsafeInterleaveIO :: IO a -> IO a\r\nunsafeInterleaveIO m = unsafeDupableInterleaveIO (noDuplicate >> m)\r\n\r\n-- We believe that INLINE on unsafeInterleaveIO is safe, because the\r\n-- state from this IO thread is passed explicitly to the interleaved\r\n-- IO, so it cannot be floated out and shared.\r\n}}}\r\n\r\nIt seems the comment about INLINE is not true. If I define the following function:\r\n\r\n{{{\r\ninterleave :: IO a -> IO a\r\ninterleave = unsafeInterleaveIO\r\n{-# NOINLINE interleave #-}\r\n}}}\r\n\r\nand replace unsafeInterleaveIO with interleave, \"eval\" is printed only once. If I change NOINLINE to INLINE, or if I remove the pragma altogether, \"eval\" is printed 1000 times.\r\n\r\nI believe unsafeInterleaveIO should ''guarantee'' that computations are not repeated. Otherwise, we end up with strangeness like this:\r\n\r\n{{{\r\nimport Control.Applicative\r\nimport Control.Concurrent\r\nimport Control.Monad\r\n\r\nmain :: IO ()\r\nmain = do\r\n chan <- newChan :: IO (Chan Int)\r\n mapM_ (writeChan chan) [0..999]\r\n items <- take 10 <$> getChanContents chan\r\n replicateM_ 5 $ forkIO $ putStrLn $ \"items = \" ++ show items\r\n threadDelay 1000000\r\n}}}\r\n\r\nwhich prints:\r\n\r\n{{{\r\nitems = [0,1,2,3,4,5,6,7,8,9]\r\nitems = [10,11,12,13,14,15,16,17,18,19]\r\nitems = [20,21,22,23,24,25,26,27,28,29]\r\nitems = [30,31,32,33,34,35,36,37,38,39]\r\nitems = [40,41,42,43,44,45,46,47,48,49]\r\n}}}\r\n\r\nFor the time being, programs can work around this by using a NOINLINE wrapper:\r\n\r\n{{{\r\ngetChanContents' :: Chan a -> IO [a]\r\ngetChanContents' = getChanContents\r\n{-# NOINLINE getChanContents' #-}\r\n}}}\r\n\r\nI tested this on Linux 64-bit with GHC 7.2.2 and ghc-7.4.0.20120111, and on Windows 32-bit with GHC 7.0.3 and 7.2.2. All of these platforms and versions exhibit the same behavior. The bug goes away when the program is compiled with -O0, or when functions returning interleaved computations are marked NOINLINE (e.g. getChanContents').","type_of_failure":"OtherFailure","blocking":[]} -->Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/21973GHC produces Core with an infinite <<loop>> v32024-01-14T22:00:06ZAlexey KuleshevichGHC produces Core with an infinite <<loop>> v3## Summary
This feels like deja vu. :smile: Every two years I report a very similar bug. Last one was fixed in ghc-8.10.2 while this one is reproducible with: ghc-8.10.7, ghc-9.0. and ghc-9.2.4 (haven't tried the HEAD). Maybe third time...## Summary
This feels like deja vu. :smile: Every two years I report a very similar bug. Last one was fixed in ghc-8.10.2 while this one is reproducible with: ghc-8.10.7, ghc-9.0. and ghc-9.2.4 (haven't tried the HEAD). Maybe third time is the charm. Considering that all of them where discovered on totally different projects, I am feeling pretty lucky.
Here are the prior bugs, in case that they are in fact related:
* #17151
* #13429
A specific relation of type families and type classes causes GHC to generate code that will either:
* crash with `<<loop>>` or actually never terminate when compiled with optimizations
* die with OOM (Out Of Memory) when compiled with `-O0`
## Steps to reproduce
Compile this snippet and run it:
```haskell
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Main (main) where
import Data.Kind
newtype Decoder a = Decoder (String -> a)
class Monoid (Share a) => From a where
type Share a :: Type
decoderWithShare :: Share a -> Decoder a
decode :: From a => String -> a
decode str =
case decoderWithShare mempty of
Decoder f -> f str
class (Ord (Currency e), From (Tx e)) => Ledger e where
--class Ord (Currency e) => Ledger e where
type Currency e :: Type
type Tx e :: Type
data MyLedger c
newtype MyTx c = MyTx
{ currency :: c
} deriving (Show, Read)
instance (Read c, Ord c) => Ledger (MyLedger c) where
type Currency (MyLedger c) = c
type Tx (MyLedger c) = MyTx c
instance (Read c, Ledger (MyLedger c)) => From (MyTx c) where
type Share (MyTx c) = [c]
decoderWithShare s =
Decoder $ \str ->
let c = read str
in MyTx $ if elem c s then c else c
main :: IO ()
main = print (decode (show (currency (MyTx "USD"))) :: MyTx String)
```
When compiled with optimizations it results in `<<loop>>`
```
$ ghc loop.hs -fforce-recomp -O && ./loop
[1 of 1] Compiling Main ( loop.hs, loop.o )
Linking loop ...
loop: <<loop>>
```
while without optimizations will not terminate and crash the process with OOM:
```
$ ghc loop.hs -fforce-recomp && ./loop
[1 of 1] Compiling Main ( loop.hs, loop.o )
Linking loop ...
^C
```
I'd also like to note a few points:
* This is the minimal example I could come up with, the original is way too complex to be included
* Type families do not have to be associated
* In the codebase where the bug was discovered:
* It actually goes into infinite loop, i.e. no `<<loop>>` detection.
* It was necessary for the constraint to be present as well for the bug to trigger: `Share (Tx e) ~ [Currency e]`:
```
class (Ord (Currency e), From (Tx e), Share (Tx e) ~ [Currency e]) => Ledger e where
```
## Expected behavior
Regardless of ghc flags the expected output should be:
```
$ ghc loop.hs -fforce-recomp -O && ./loop
[1 of 1] Compiling Main ( loop.hs, loop.o )
Linking loop ...
MyTx {currency = "USD"}
```
Which can be observed when commented out line is used instead of the one that triggers the bug:
```
-class (Ord (Currency e), From (Tx e)) => Ledger e where
+class Ord (Currency e) => Ledger e where
```
Above adjustment will cause the bug to disappear. Other minor changes can have the same affect, so this bug is a bit sensitive.
At a quick glance this seems to be the part of Core that is the offender here: https://github.com/lehins/bugs/blob/master/haskell/ghc-infinite-loop/minimal/loop-O1.dump-simpl#L100-L132 Although I am pretty far from being a Core expert, so I might be totally wrong.
## Environment
* GHC version used: 8.10.7, 9.0.2 and 9.2.4
Optional:
* Operating System: NixOS and OpenSUSE
* System Architecture: x86_649.4.3Andreas KlebingerAndreas Klebingerhttps://gitlab.haskell.org/ghc/ghc/-/issues/5129"evaluate" optimized away2023-12-15T20:11:41Zdons"evaluate" optimized awayReported on Stackoverflow: http://stackoverflow.com/questions/5697159/testing-for-error-calls-in-hunit
With optimizations on, the following program, which normally succeeds (correctly generating an exception), instead fails, and the exc...Reported on Stackoverflow: http://stackoverflow.com/questions/5697159/testing-for-error-calls-in-hunit
With optimizations on, the following program, which normally succeeds (correctly generating an exception), instead fails, and the exception is optimized away.
```
import Control.Exception
import Test.HUnit
throwIfNegative :: Int -> String
throwIfNegative n | n < 0 = error "negative"
| otherwise = "no worries"
{-# NOINLINE throwIfNegative #-}
case_negative =
handleJust errorCalls (const $ return ()) $ do
evaluate $ throwIfNegative (-1)
assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
main = runTestTT $ TestCase case_negative
```
Looking at the core, after a few iterations, the call to `throwIfNegative` is dropped as dead code.
Using seq instead of evaluate is happy enough:
```
case_negative =
handleJust errorCalls (const $ return ()) $ do
throwIfNegative (-1) `seq` assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
```
or a bang pattern:
```
case_negative =
handleJust errorCalls (const $ return ()) $ do
let !x = throwIfNegative (-1)
assertFailure "must throw when given a negative number"
where errorCalls (ErrorCall _) = Just ()
```
Possibly related to #2273
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.0.3 |
| 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":"\"evaluate\" optimized away","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.0.3","keywords":["evaluate","seq,"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Reported on Stackoverflow: http://stackoverflow.com/questions/5697159/testing-for-error-calls-in-hunit\r\n\r\nWith optimizations on, the following program, which normally succeeds (correctly generating an exception), instead fails, and the exception is optimized away.\r\n\r\n{{{\r\nimport Control.Exception\r\nimport Test.HUnit\r\n\r\nthrowIfNegative :: Int -> String\r\nthrowIfNegative n | n < 0 = error \"negative\"\r\n | otherwise = \"no worries\"\r\n{-# NOINLINE throwIfNegative #-}\r\n\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n evaluate $ throwIfNegative (-1)\r\n assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n\r\nmain = runTestTT $ TestCase case_negative\r\n}}}\r\n\r\nLooking at the core, after a few iterations, the call to `throwIfNegative` is dropped as dead code.\r\n\r\nUsing seq instead of evaluate is happy enough:\r\n\r\n{{{\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n throwIfNegative (-1) `seq` assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n}}}\r\n\r\nor a bang pattern:\r\n\r\n{{{\r\ncase_negative =\r\n handleJust errorCalls (const $ return ()) $ do\r\n let !x = throwIfNegative (-1)\r\n assertFailure \"must throw when given a negative number\"\r\n where errorCalls (ErrorCall _) = Just ()\r\n}}}\r\n\r\nPossibly related to #2273","type_of_failure":"OtherFailure","blocking":[]} -->8.4.2Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/24112Unregisterised build error since haddock bump2023-12-01T15:06:10ZStefan Schulze FrielinghausUnregisterised build error since haddock bump## Summary
Since commit 1578215fd24c8b50b9d7d6cfc35e274b71dcff1a building an unregisterised GHC on s390x leads to the following error:
```
Command line: _build/stage0/bin/ghc -Wall -Wcompat -dynamic-too -hisuf hi -osuf o -hcsuf hc -sta...## Summary
Since commit 1578215fd24c8b50b9d7d6cfc35e274b71dcff1a building an unregisterised GHC on s390x leads to the following error:
```
Command line: _build/stage0/bin/ghc -Wall -Wcompat -dynamic-too -hisuf hi -osuf o -hcsuf hc -static -hide-all-packages -no-user-package-db '-package-env -' '-package-db _build/stage1/inplace/package.conf.d' '-this-unit-id template-haskell-2.21.0.0-inplace' '-package-id base-4.19.0.0-inplace' '-package-id ghc-boot-th-9.9-inplace' '-package-id ghc-prim-0.10.0-inplace' '-package-id pretty-1.1.3.6-inplace' -i -i/devel/ghc/master/_build/stage1/libraries/template-haskell/build -i/devel/ghc/master/_build/stage1/libraries/template-haskell/build/autogen -i/devel/ghc/master/libraries/template-haskell/vendored-filepath -i/devel/ghc/master/libraries/template-haskell -Irts/include -I_build/stage1/libraries/template-haskell/build -I/devel/ghc/master/libraries/base/include -I/devel/ghc/master/_build/stage1/libraries/base/build/include -I/devel/ghc/master/libraries/ghc-bignum/include/ -I/devel/ghc/master/_build/stage1/libraries/ghc-bignum/build/include/ -I/devel/ghc/master/rts/include -I/devel/ghc/master/_build/stage1/rts/build/include -optP-include -optP_build/stage1/libraries/template-haskell/build/autogen/cabal_macros.h -outputdir _build/stage1/libraries/template-haskell/build -fdiagnostics-color=always -Wall -this-unit-id template-haskell -XHaskell2010 -XImplicitPrelude -no-global-package-db -package-db=/devel/ghc/master/_build/stage1/inplace/package.conf.d -ghcversion-file=rts/include/ghcversion.h -ghcversion-file=rts/include/ghcversion.h -Wnoncanonical-monad-instances -optc-Wno-error=inline -c libraries/template-haskell/Language/Haskell/TH/Syntax.hs -o _build/stage1/libraries/template-haskell/build/Language/Haskell/TH/Syntax.o -O2 -H32m -haddock -Wno-deprecated-flags
===> Command failed with error code: 1
<command line>: unknown unit: template-haskell
Command failed
Build failed.
```
Any idea what could have gone wrong?
## Steps to reproduce
```
./boot && ./configure --enable-unregisterised && ./hadrian/build -j
```
## Environment
* GHC version used: 9.4.4
Optional:
* Operating System: Fedora 37
* System Architecture: s390xhttps://gitlab.haskell.org/ghc/ghc/-/issues/5807DPH library functions don't work without -fvectorise.2023-12-01T14:07:08ZbenlDPH library functions don't work without -fvectorise.Mukesh Tiwari reports:
```
ghci>import Data.Array.Parallel
ghci>import Data.Array.Parallel.PArray
ghci>let u = Data.Array.Parallel.PArray.fromList [ 1 .. 10 ]
ghci>:t u
u :: PArray Double
ghci>u
fromList<PArray> [1.0,2.0,3.0,4.0,5.0,6....Mukesh Tiwari reports:
```
ghci>import Data.Array.Parallel
ghci>import Data.Array.Parallel.PArray
ghci>let u = Data.Array.Parallel.PArray.fromList [ 1 .. 10 ]
ghci>:t u
u :: PArray Double
ghci>u
fromList<PArray> [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]
ghci>let v = Data.Array.Parallel.fromPArrayP u
ghci>:t v
v :: [:Double:]
ghci>lengthP v
0
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------------- |
| Version | 7.2.2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Data Parallel Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"lengthP returns bad result","status":"New","operating_system":"","component":"Data Parallel Haskell","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"benl"},"version":"7.2.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"\r\nMukesh Tiwari reports:\r\n\r\n{{{\r\nghci>import Data.Array.Parallel\r\nghci>import Data.Array.Parallel.PArray \r\nghci>let u = Data.Array.Parallel.PArray.fromList [ 1 .. 10 ]\r\nghci>:t u\r\nu :: PArray Double\r\nghci>u\r\nfromList<PArray> [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0]\r\nghci>let v = Data.Array.Parallel.fromPArrayP u\r\nghci>:t v\r\nv :: [:Double:]\r\nghci>lengthP v\r\n0\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->⊥benlbenlhttps://gitlab.haskell.org/ghc/ghc/-/issues/16258PowerPC Big-Endian: ArithInt16, ArithInt8, ArithWord16, and ArithWord8 fail2023-10-25T09:09:04ZPeter Trommlerptrommler@acm.orgPowerPC Big-Endian: ArithInt16, ArithInt8, ArithWord16, and ArithWord8 failThe tests were run on a PowerMac G5 running Linux, PowerMacs are big-endian.
I reduced the issue to this program where I get the incorrect answer `25132`:
```hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE Unbo...The tests were run on a PowerMac G5 running Linux, PowerMacs are big-endian.
I reduced the issue to this program where I get the incorrect answer `25132`:
```hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
module Main where
import GHC.Exts
main :: IO ()
main = do
putStrLn $ show (apply2 plusInt16# (50) (50))
apply2 :: (Int16# -> Int16# -> Int16#) -> Int -> Int -> Int
apply2 op (I# a) (I# b) =
let (# sa, sb #) = (# narrowInt16# a, narrowInt16# b #)
r = op sa sb
in I# (extendInt16# r)
{-# NOINLINE apply2 #-}
```
Curiously, when I inline `plusInt16#` and remove the op parameter the result is correct.
The test passes on little-endian PowerPC 64-bit.
Note: This bug is different from #16222, which deals with the C calling convention.8.10.1Peter Trommlerptrommler@acm.orgPeter Trommlerptrommler@acm.orghttps://gitlab.haskell.org/ghc/ghc/-/issues/18431Unboxed types in GHCi on big-endian platforms2023-10-25T09:03:58ZStefan Schulze FrielinghausUnboxed types in GHCi on big-endian platforms## Summary
Consider a file `test.hs` with content as follows:
```haskell
{-# LANGUAGE MagicHash #-}
module Main where
import GHC.Exts
data Foo = Foo Float# deriving Show
main = print $ Foo 1.0#
```
If compiled on s390x via LLVM backen...## Summary
Consider a file `test.hs` with content as follows:
```haskell
{-# LANGUAGE MagicHash #-}
module Main where
import GHC.Exts
data Foo = Foo Float# deriving Show
main = print $ Foo 1.0#
```
If compiled on s390x via LLVM backend and executed the expected output `Foo 1.0#` is printed to stdout. However, if interpreted via GHCi, the output is wrong:
```
> :load test.hs
> main
Foo 0.0#
```
This might be a big-endian bug. I tried to follow the execution of GHCi via GDB but got lost in to many continuations. I also had a look into parts of GHCi without luck. Any hint which parts of GHCi are responsible for interpreting unboxed types?
This is also the reason why test `T13825-debugger` fails on s390x.
Note, a similar bug regarding GHCi using `:print` is fixed by !3649.Stefan Schulze FrielinghausStefan Schulze Frielinghaushttps://gitlab.haskell.org/ghc/ghc/-/issues/23749Aarch64 NCG doesn't always uphold the invariants mentioned in `Note [Signed a...2023-10-11T12:58:57ZAndreas KlebingerAarch64 NCG doesn't always uphold the invariants mentioned in `Note [Signed arithmetic on AArch64]`The Note describes this invariant:
```
-- We handle 16-and 8-bit values by using the 32-bit operations and
-- sign-/zero-extending operands and truncate results as necessary. For
-- simplicity we maintain the invariant that a register c...The Note describes this invariant:
```
-- We handle 16-and 8-bit values by using the 32-bit operations and
-- sign-/zero-extending operands and truncate results as necessary. For
-- simplicity we maintain the invariant that a register containing a
-- sub-word-size value always contains the zero-extended form of that value
-- in between operations.
```
However the fast path for addition with immediate doesn't uphold this. There we have:
```
CmmMachOp (MO_Add w) [(CmmReg reg), CmmLit (CmmInt n _)]
| n > 0 && n < 4096 -> return $ Any (intFormat w) (\d -> unitOL $ annExpr expr (ADD (OpReg w d) (OpReg w' r') (OpImm (ImmInteger n))))
-- TODO: 12bits lsl #12; e.g. lower 12 bits of n are 0; shift n >> 12, and set lsl to #12.
where w' = formatToWidth (cmmTypeFormat (cmmRegType reg))
r' = getRegisterReg plat reg
```
Which means expressions such as `reg + 1` can overflow the high bits resulting in a violation of the invariant.
I wasn't (yet) able to make this go wrong on a larger scale, as we don't seem to really rely on this invariant much (and re-zero in most other places). Best I could do was this cmm:
```C
high_bits(I16 x) {
A:
I16 y;
y = x + 1;
call foo(y);
}
```
Resulting in foo being called with a high bit potentially set depending on the initial value of x:
```
mov w18, w22
add w18, w18, #1
adrp x17, .Lblock_c4_info
add x17, x17, :lo12:.Lblock_c4_info
str x17, [ x20, -8 ]
mov x22, x18
sub x20, x20, #8
b foo
```
Maybe this could cause issues in mac where we are responsible for zeroing out the high bits. But I won't spend more time on what issues this can cause I will just fix it.9.4.6Andreas KlebingerAndreas Klebingerhttps://gitlab.haskell.org/ghc/ghc/-/issues/23980Incorrect filesize and timestamps for JavaScript backend2023-10-05T21:41:48ZLuite StegemanIncorrect filesize and timestamps for JavaScript backendThe JavaScript backend still has some bugs when filling the `stat` data used in the `FileStatus` data structure:
Some issues I've found:
* the time fields (`st_atime`/`st_mtime`/`st_ctime`) fields are filled assuming that the size re...The JavaScript backend still has some bugs when filling the `stat` data used in the `FileStatus` data structure:
Some issues I've found:
* the time fields (`st_atime`/`st_mtime`/`st_ctime`) fields are filled assuming that the size reported by the `configure` script is for whole `timespec` struct, which results in 32 bit for the seconds + 32 bit for nanoseconds. In reality `stat.st_mtime` is actually defined to be `stat.st_mtim.tv_sec` and should be 64 bit.
* the large field `st_size` is filled in the wrong order, resulting in the wrong size being decoded.
I'm working on a fix and adding a test that tests these basic file properties so that we can find them in a simple test (instead in something strange going wrong in cabal/backpack tests)9.8.2Luite StegemanLuite Stegemanhttps://gitlab.haskell.org/ghc/ghc/-/issues/22998Wrong result for modulo arithmetic with GHC 9.42023-09-18T21:44:50ZLars KuhtzWrong result for modulo arithmetic with GHC 9.4## Summary
With GHC-9.4.4 and optimization enabled (`-O1` or `-O2`) I have been observing erroneous results for `newtype`s over `Mod q` from the `mod` package for q ≥ 2^64.
The buggy behavior appears only with GHC-9.4 and only when op...## Summary
With GHC-9.4.4 and optimization enabled (`-O1` or `-O2`) I have been observing erroneous results for `newtype`s over `Mod q` from the `mod` package for q ≥ 2^64.
The buggy behavior appears only with GHC-9.4 and only when optimization is enabled. This indicates that it may be a bug in GHC-9.4. Moreover, the manifestation of the bug is somewhat non-deterministic. In particular it varies based on where code is placed (same or other module) and whether unrelated code is compiled along with the problematic code.
## Steps to reproduce
Building and running the following program with `cabal run -w ghc-9.4.4 Main.hs` (`-O1` enabled) prints `0` to the terminal.
```Haskell
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (main) where
import Data.Mod (Mod)
import GHC.TypeNats (KnownNat)
import Numeric.Natural (Natural)
import Test.QuickCheck (Arbitrary, arbitrary)
import Test.QuickCheck.Instances ()
newtype Fq = Fq (Mod 18446744073709551616 {- 2^64 -}) deriving (Num)
instance KnownNat n => Arbitrary (Mod n) where
arbitrary = fromIntegral <$> arbitrary @Natural
instance Arbitrary Fq where
arbitrary = Fq <$> arbitrary
main :: IO ()
main = let Fq x = -1 in print x
-- the result will be the same for value of -2, -3, ... or 0 - 1.
```
Note, that in this example the redundant `Arbitrary` instances are required for the bug to manifest. On larger code bases I have observed the bug also without these instances in the code base.
Build dependencies:
```cabal
cabal-version: 3.0
name: mod-bug
version: 0.1.0.0
synopsis: demonstrate bug when using mod package
executable bug
main-is: Main.hs
hs-source-dirs: .
default-language: Haskell2010
build-depends:
, base ==4.17.0.0
, mod ==0.2.0.1
, QuickCheck ==2.14.2
, quickcheck-instances ==0.3.28
```
Please also see [this Github issue](https://github.com/Bodigrim/mod/issues/25) and [this gist](https://gist.github.com/larskuhtz/c216e2fd9e6aac580ea9640d554dddf8) for further details.
## Expected behavior
Above program should print: `18446744073709551615`
## Environment
GHC-9.4.4, amd64, build with `-O1` or `-O2`. The bug has been reproduced both with Linux and MacOS.
I have not been able to reproduce the bug with other versions of GHC or with `-O0`. I haven't tried on arm architectures.9.4.5Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/21229Inlining DFuns leads to an unsound interaction with Specialise2023-09-13T12:07:03ZSebastian GrafInlining DFuns leads to an unsound interaction with Specialise!7599 unveiled a bug in the Specialiser.
* See also #21328
* Test is in `simplCore/should_run/T21229`
Back to the Specialiser. Consider
```hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowA...!7599 unveiled a bug in the Specialiser.
* See also #21328
* Test is in `simplCore/should_run/T21229`
Back to the Specialiser. Consider
```hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
data B = T | F deriving Show
class Sing (b :: B) where sing :: B
instance Sing 'T where sing = T
instance Sing 'F where sing = F
f :: forall a. Sing a => Int -> (Int -> B -> B) -> B
f 0 g = g 0 (sing @a)
f n g = f @a (n-1) g
h :: forall a. Sing a => Int -> (Int -> B -> B) -> B
h = case sing @a of
T -> f @'T
F -> f @a
{-# NOINLINE h #-}
main = print $ h @'T 0 (\ _ a -> a)
```
With -O0, this prints `T`, as expected, because `h` will ultimately call its supplied argument once with `T`.
But with -O, I get `F`. Why is that? The reason is we ultimately get the following specialisation for the second call to `f`:
```
RULES: "SPEC f @a"
forall (@(a_aXu :: B)) ($dSing_s1OW :: Sing a_aXu).
f @a_aXu $dSing_s1OW
= $sf_s1OX @a_aXu]
```
and this specialisation (for when `$dSing_s1OW` is `F`) somehow also applies at `f @'T`.
FTR, here is the output of the `pprTrace "spec_call"` in Specialise:
```
spec_call
call info: CI{SpecType a_aXu
SpecDict F `cast` (Sym (N:Sing[0] <a_aXu>_N) :: B ~R# Sing a_aXu)}
useful: True
rule_bndrs: [a_aXu, $dSing_s1OW]
lhs_args: [TYPE: a_aXu, $dSing_s1OW]
spec_bndrs: [a_aXu]
spec_args: [TYPE: a_aXu,
F `cast` (Sym (N:Sing[0] <a_aXu>_N) :: B ~R# Sing a_aXu)]
dx_binds: []
rhs_env2: <InScope = {main g_aC8 a_aXu $cshowsPrec_aY5 $cshow_aYd
$cshowList_aYl $krep_aZ1 $krep_aZ2 $krep_aZ3 $krep_aZ4 $krep_aZ5
$krep_aZ6 ds_dZX main $fShowB $fSingF F $fSingT $tc'C:Sing
$trModule $tc'F $tc'T $tcB $tcSing f h main_s19F main_s19G
main_s1OF $trModule_s1OG $trModule_s1OH $trModule_s1OI
$trModule_s1OJ $krep_s1OK $tcB_s1OL $tcB_s1OM $tc'T_s1ON $tc'T_s1OO
$tc'F_s1OP $tc'F_s1OQ $tcSing_s1OR $tcSing_s1OS $krep_s1OT
$tc'C:Sing_s1OU $tc'C:Sing_s1OV}
IdSubst = [aKV :-> F
`cast` (Sym (N:Sing[0] <a_aXu>_N) :: B ~R# Sing a_aXu)]
TvSubst = [aKU :-> a_aXu]
CvSubst = []>
[]
```
How did it come to this?! For that we have to look at the Core of `h` that Specialise sees:
```
h = \ (@(a_aWY :: B))
($dSing_aWZ :: Sing a_aWY)
(eta_B0 :: Int)
(eta_B1 :: Int -> B -> B) ->
case $dSing_aWZ
`cast` (Main.N:Sing[0] <a_aWY>_N :: Sing a_aWY ~R# B)
of {
T ->
f @'T
(Main.T `cast` (Sym (Main.N:Sing[0] <'T>_N) :: B ~R# Sing 'T))
eta_B0
eta_B1;
F ->
f @a_aWY
(Main.F
`cast` (Sym (Main.N:Sing[0] <a_aWY>_N) :: B ~R# Sing a_aWY))
eta_B0
eta_B1
}
```
Note the second call to `f`. The type argument `a_aWY` is passed, as well as `Main.F` as the dictionary. That's strange! We should know *statically* that `a_aWY` must be `F`. (In fact, ``Main.F `cast` (Sym (Main.N:Sing[0] <a_aWY>_N) :: B ~R# Sing a_aWY)`` is unsound if `a_aWY` is instantiated to `T`, which would perhaps happen if we floated that expression out of the `F` case. I guess it doesn't matter much, at least not to this ticket.)
How did we get this code? After desugaring, we still have
```
h = \ (@(a_aXu :: B)) ($dSing_aXv :: Sing a_aXu) ->
case sing @a_aXu $dSing_aXv of {
T -> f @'T Main.$fSingT;
F -> f @a_aXu $dSing_aXv
}
```
But then gentle simplification inlines `sing` and sees that `$dSing_aXv` is `F` in the `F` case, performs a binder swap and successively inlines `F` (at least that's what I believe the Simplifier does).
Then the Specialiser can't connect `F` to the arguments `$dSing_aXv` or the type arg `a` and somehow bogs up. I suspect this happens in `specHeader`, but actually I'm not completely sure.
I couldn't reproduce with GHC 9.2 and any prior release. I see that we get the same Core pre-Specialise, but it is handled soundly there and we only get a specialisation for `T`. So perhaps we want to fix this before 9.4.9.4.1https://gitlab.haskell.org/ghc/ghc/-/issues/9817signal handlers in unix are passed garbage when using the signle threaded rts2023-09-09T22:39:58Zrednebsignal handlers in unix are passed garbage when using the signle threaded rtsWhen a signal handler (registered with `GHC.Conc.Signal.setHandler`) is called upon the receipt of the relevant signal, it is passed a memory buffer in the form of a `ForeignPtr Word8`. This buffer contains a copy of the `siginfo_t` stru...When a signal handler (registered with `GHC.Conc.Signal.setHandler`) is called upon the receipt of the relevant signal, it is passed a memory buffer in the form of a `ForeignPtr Word8`. This buffer contains a copy of the `siginfo_t` struct that was originally passed to the underlying os signal handler. Unfortunately, this only seems to work correctly in the threaded rts. In the single-threaded rts, the buffer contains garbage. This can be demonstrated by the following program:
```hs
import Control.Concurrent
import System.Posix.Signals
main :: IO ()
main = do
wait <- newEmptyMVar
_ <- flip (installHandler sig) Nothing $ CatchInfo $ \info -> do
putStrLn $ "Received a signal " ++ show (siginfoSignal info)
putMVar wait ()
raiseSignal sig
putStrLn $ "Sending myself a signal " ++ show sig
takeMVar wait
where
sig = sigUSR2
```
If you compile the program with the `-threaded` flag then everything works just fine:
```
Sending myself a signal 12
Received a signal 12
```
but without it, the signal handler will print a totaly random signal number:
```
Sending myself a signal 12
Received a signal 138644296
```
I was able to track this down to the function `startSignalHandlers` in `rts/posix/Signals.c`. This function (which is only used by the single threaded rts) allocates a buffer and copies the `siginfo_t` struct to it and then schedules `GHC.Conc.Signal.runHandlers` to be run in a new thread. The problem is that while `GHC.Conc.Signal.runHandlers` expects a `ForeignPtr Word8`, here it is given a `Ptr Word8`. This has two implications: the signal handler is given invalid data, and nobody is deallocating the buffer so we are leaking memory every time a signal is received that has a custom handler.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Runtime System |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | simonmar |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"signal handlers in unix are passed garbage when using the signle threaded rts","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"simonmar"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["simonmar"],"type":"Bug","description":"When a signal handler (registered with `GHC.Conc.Signal.setHandler`) is called upon the receipt of the relevant signal, it is passed a memory buffer in the form of a `ForeignPtr Word8`. This buffer contains a copy of the `siginfo_t` struct that was originally passed to the underlying os signal handler. Unfortunately, this only seems to work correctly in the threaded rts. In the single-threaded rts, the buffer contains garbage. This can be demonstrated by the following program:\r\n\r\n{{{#!hs\r\nimport Control.Concurrent\r\nimport System.Posix.Signals\r\n\r\nmain :: IO ()\r\nmain = do\r\n wait <- newEmptyMVar\r\n _ <- flip (installHandler sig) Nothing $ CatchInfo $ \\info -> do\r\n putStrLn $ \"Received a signal \" ++ show (siginfoSignal info)\r\n putMVar wait ()\r\n raiseSignal sig\r\n putStrLn $ \"Sending myself a signal \" ++ show sig\r\n takeMVar wait\r\n where\r\n sig = sigUSR2\r\n}}}\r\n\r\nIf you compile the program with the `-threaded` flag then everything works just fine:\r\n{{{\r\nSending myself a signal 12\r\nReceived a signal 12\r\n}}}\r\nbut without it, the signal handler will print a totaly random signal number:\r\n{{{\r\nSending myself a signal 12\r\nReceived a signal 138644296\r\n}}}\r\n\r\nI was able to track this down to the function `startSignalHandlers` in `rts/posix/Signals.c`. This function (which is only used by the single threaded rts) allocates a buffer and copies the `siginfo_t` struct to it and then schedules `GHC.Conc.Signal.runHandlers` to be run in a new thread. The problem is that while `GHC.Conc.Signal.runHandlers` expects a `ForeignPtr Word8`, here it is given a `Ptr Word8`. This has two implications: the signal handler is given invalid data, and nobody is deallocating the buffer so we are leaking memory every time a signal is received that has a custom handler.","type_of_failure":"OtherFailure","blocking":[]} -->7.8.4Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/16089seq is not cooperating with :sprint in GHCi as expected2023-08-29T00:32:45Zradrowseq is not cooperating with :sprint in GHCi as expectedI was playing around with strictness and performed following test:
```hs
Prelude> x = [True, False]
Prelude> :sprint x
x = _
Prelude> x `seq` True
True
Prelude> :sprint x
x = _
```
I completely don't understand why `x = _` at this mome...I was playing around with strictness and performed following test:
```hs
Prelude> x = [True, False]
Prelude> :sprint x
x = _
Prelude> x `seq` True
True
Prelude> :sprint x
x = _
```
I completely don't understand why `x = _` at this moment. `seq` must evaluate one level of `x` achieving `x = True : _` to ensure that it is not `undefined`, so why is this information lost?
I am testing it on GHCi version 8.6.3, but it is not reproducible on other versions (checked on 8.4.4, 8.2.2 and 7._._).
I have asked about it on SO, so if this behavior is intended I kindly ask for explaination here [https://stackoverflow.com/questions/53898220/sprint-and-seq-together-missing-evaluation](https://stackoverflow.com/questions/53898220/sprint-and-seq-together-missing-evaluation) to let others know.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | GHCi |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"seq is not cooperating with :sprint in GHCi as expected","status":"New","operating_system":"","component":"GHCi","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.6.3","keywords":["seq","sprint","strictness"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I was playing around with strictness and performed following test:\r\n\r\n{{{#!hs\r\nPrelude> x = [True, False]\r\nPrelude> :sprint x\r\nx = _\r\nPrelude> x `seq` True\r\nTrue\r\nPrelude> :sprint x\r\nx = _\r\n}}}\r\n\r\nI completely don't understand why `x = _` at this moment. `seq` must evaluate one level of `x` achieving `x = True : _` to ensure that it is not `undefined`, so why is this information lost? \r\n\r\nI am testing it on GHCi version 8.6.3, but it is not reproducible on other versions (checked on 8.4.4, 8.2.2 and 7._._). \r\n\r\nI have asked about it on SO, so if this behavior is intended I kindly ask for explaination here [https://stackoverflow.com/questions/53898220/sprint-and-seq-together-missing-evaluation] to let others know.","type_of_failure":"OtherFailure","blocking":[]} -->8.8.1