GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T18:46:01Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/8213Bad error message when using lazy IO to read from closed handle2019-07-07T18:46:01ZNiklas Hambüchenmail@nh2.meBad error message when using lazy IO to read from closed handleToday I accidentally wrote this code:
```
import System.IO
import Data.ByteString.Lazy as BSL
filesEqual :: FilePath -> FilePath -> IO Bool
filesEqual f1 f2 = do
equal <- withBinaryFile f1 ReadMode $ \h1 ->
withBinaryFile f2 Read...Today I accidentally wrote this code:
```
import System.IO
import Data.ByteString.Lazy as BSL
filesEqual :: FilePath -> FilePath -> IO Bool
filesEqual f1 f2 = do
equal <- withBinaryFile f1 ReadMode $ \h1 ->
withBinaryFile f2 ReadMode $ \h2 -> do
c1 <- BSL.hGetContents h1
c2 <- BSL.hGetContents h2
return (c1 == c2)
return $! equal
main = filesEqual "test.hs" "test.hs" >>= print
```
The problem is that I should have done the forcing before the files are closed:
```
return $! (c1 == c2)
```
I got the incredibly unhelpful error message
```
test: test.hs: illegal operation
```
It took me 2 hours and strace to find out what was going on, especially because around every file open() there are multiple things that map top IllegalOperation (e.g. the ENOTTY from the ioctl that checks whether the device is a TTY).
Can we give a better error message here, at least mentioning that the problem has to do with closed (and GC'd) handles?https://gitlab.haskell.org/ghc/ghc/-/issues/8188about template haskell's pretty print: 3 % 5 -> 3 / 52019-07-07T18:46:07ZYoshikuniJujoabout template haskell's pretty print: 3 % 5 -> 3 / 5I think it's better that the ghc can read what is printed by pretty printer.
Now:
pprLit 0 (RationalL 3.5) =\> 7 % 2
I want:
# \> 7 / 2
I'll send patch.
<details><summary>Trac metadata</summary>
| Trac field | Value ...I think it's better that the ghc can read what is printed by pretty printer.
Now:
pprLit 0 (RationalL 3.5) =\> 7 % 2
I want:
# \> 7 / 2
I'll send patch.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"about template haskell's pretty print: 3 % 5 -> 3 / 5","status":"New","operating_system":"","component":"Template Haskell","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":["RationalL","haskell","pretty","print","template"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I think it's better that the ghc can read what is printed by pretty printer.\r\n\r\nNow:\r\n\r\npprLit 0 (RationalL 3.5) => 7 % 2\r\n\r\nI want:\r\n\r\n=> 7 / 2\r\n\r\nI'll send patch.","type_of_failure":"OtherFailure","blocking":[]} -->Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/8187about template haskell's pretty print: ($$$) xy = ...2019-07-07T18:46:08ZYoshikuniJujoabout template haskell's pretty print: ($$$) xy = ...Language.Haskell.TH.Ppr
Now:
ppr $ FunD (mkName "$$" \[Clause \[\] (NormalB $ VarE $ mkName "x") \[\]\]
=\> $$ = x
I want:
# \> ($$) = x
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ----...Language.Haskell.TH.Ppr
Now:
ppr $ FunD (mkName "$$" \[Clause \[\] (NormalB $ VarE $ mkName "x") \[\]\]
=\> $$ = x
I want:
# \> ($$) = x
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ---------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Template Haskell |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"about template haskell's pretty print: ($$$) xy = ...","status":"New","operating_system":"","component":"Template Haskell","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Language.Haskell.TH.Ppr\r\n\r\nNow:\r\n\r\nppr $ FunD (mkName \"$$\" [Clause [] (NormalB $ VarE $ mkName \"x\") []]\r\n=> $$ = x\r\n\r\nI want:\r\n\r\n=> ($$) = x","type_of_failure":"OtherFailure","blocking":[]} -->Simon Peyton JonesSimon Peyton Joneshttps://gitlab.haskell.org/ghc/ghc/-/issues/8083setNumCapabilities broken in HEAD2019-07-07T18:46:34ZparcssetNumCapabilities broken in HEAD```haskell
import GHC.Conc
import Control.Monad
main :: IO ()
main = do
n <- getNumCapabilities
when (n == 1) $ setNumCapabilities 2
print ()
```
One would expect this program to print () just once, but when compiled with -...```haskell
import GHC.Conc
import Control.Monad
main :: IO ()
main = do
n <- getNumCapabilities
when (n == 1) $ setNumCapabilities 2
print ()
```
One would expect this program to print () just once, but when compiled with -O or -O2 it prints () repeatedly and indefinitely!
This doesn't happen on GHC 7.6.2 or 7.4.1, only on HEAD.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.7 |
| 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":"setNumCapabilities broken in HEAD","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{\r\n#!haskell\r\nimport GHC.Conc\r\nimport Control.Monad\r\n\r\nmain :: IO ()\r\nmain = do\r\n n <- getNumCapabilities\r\n when (n == 1) $ setNumCapabilities 2\r\n print ()\r\n}}}\r\n\r\nOne would expect this program to print () just once, but when compiled with -O or -O2 it prints () repeatedly and indefinitely!\r\n\r\nThis doesn't happen on GHC 7.6.2 or 7.4.1, only on HEAD.","type_of_failure":"OtherFailure","blocking":[]} -->7.8.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/7997waitForProcess and getProcessExitCode are unsafe against asynchronous except...2019-07-07T18:47:07ZdfrankewaitForProcess and getProcessExitCode are unsafe against asynchronous exceptionsIn this description of the current behavior of *waitForProcess*, assume for simplicity the following:
1. The process being waited on has already terminated.
1. Neither *waitForProcess* nor *getProcessExitCode* has previously been called...In this description of the current behavior of *waitForProcess*, assume for simplicity the following:
1. The process being waited on has already terminated.
1. Neither *waitForProcess* nor *getProcessExitCode* has previously been called for this *ProcessHandle*.
1. *waitpid()* returns success on the first try; it does not get interrupted by a signal.
Under these assumptions, *waitForProcess* currently behaves as follows:
1. It is passed a *ProcessHandle* named *ph*. *ProcessHandle* is defined like so:
```
data ProcessHandle__ = OpenHandle PHANDLE | ClosedHandle ExitCode
newtype ProcessHandle = ProcessHandle (MVar ProcessHandle__)
```
1. It allocate a *CInt* using *alloca*; the pointer to it is named *pret*.
1. It passes *pret* to *c_waitForProcess*. *c_waitForProcess* makes a system call to *waitpid()*, and populates *pret* with the result.
1. *waitForProcess* peeks into *pret* and then mutates *ph*, changing it from an *OpenHandle* to a *ClosedHandle*.
There is already a comment in the source code mentioning that this approach is unsafe:
```
-- don't hold the MVar while we call c_waitForProcess...
-- (XXX but there's a small race window here during which another
-- thread could close the handle or call waitForProcess)
```
, which is correct. However, it is also unsafe against asynchronous exceptions, and would remain so even if the *MVar* were held during the *c_waitForProcess* call. If an asynchronous exception occurs in between steps 3 and 4, then the system will be left in a state in which the child process has been successfully waited on by the OS, but the *ProcessHandle* is still in an *OpenHandle* state and the exit code has been lost. A subsequent call to *waitForProcess* will result in *waitpid()* unexpectedly returning ECHILD, or worse, the OS will have recycled the child process's PID and *waitpid()* will wait on the wrong process.
*getProcessExitCode* has the same bug.
I propose fixing this by redefining *ProcessHandle* like so:
```
data ProcessHandle = ProcessHandle PHANDLE (Ptr CInt) (MVar (Ptr CInt))
```
, where the second argument maybe points to the process's return code, and the third argument contains a pointer to a boolean flag indicating whether the second argument points to something meaningful. Extend the signature of *c_waitForProcess* to take both pointers. Then, let *c_waitForProcess* provide the following contract. If called as *c_waitForProcess ph pret pflag*:
1. *\*pflag* is required to be false at the start of the call.
1. If and only if the call to *waitpid()* returns successfully, then *\*pflag* will be set to true and *\*pret* will be populated with the exit code.
Then, *waitForProcess* can behave as follows:
1. The entire routine is wrapped in *withMVar*. Asynchronous exceptions are allowed to occur.
1. If *\*pflag* is true, then construct an *ExitCode* from *\*pret* and return it.
1. Otherwise, call *c_waitForProcess* (with the same retry behavior as presently), and then construct and return an *ExitCode* after a successful return.
And *getProcessExitCode* can:
1. Mask exceptions.
1. *tryTakeMVar*. If the *MVar* is already held, unmask exceptions and return *Nothing*.
1. Peek at *\*pflag*.
1. Replace the *MVar*.
1. Unmask exceptions.
1. If *\*pflag* is true, then construct and return an *ExitCode* from *\*pret*.
1. Otherwise, return *Nothing*.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/process |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"waitForProcess and getProcessExitCode are unsafe against asynchronous exceptions","status":"New","operating_system":"","component":"libraries/process","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"In this description of the current behavior of ''waitForProcess'', assume for simplicity the following:\r\n\r\n1. The process being waited on has already terminated.\r\n\r\n2. Neither ''waitForProcess'' nor ''getProcessExitCode'' has previously been called for this ''ProcessHandle''.\r\n\r\n3. ''waitpid()'' returns success on the first try; it does not get interrupted by a signal.\r\n\r\nUnder these assumptions, ''waitForProcess'' currently behaves as follows:\r\n\r\n1. It is passed a ''ProcessHandle'' named ''ph''. ''ProcessHandle'' is defined like so:\r\n\r\n{{{\r\ndata ProcessHandle__ = OpenHandle PHANDLE | ClosedHandle ExitCode\r\nnewtype ProcessHandle = ProcessHandle (MVar ProcessHandle__)\r\n}}}\r\n\r\n2. It allocate a ''CInt'' using ''alloca''; the pointer to it is named ''pret''. \r\n\r\n3. It passes ''pret'' to ''c_waitForProcess''. ''c_waitForProcess'' makes a system call to ''waitpid()'', and populates ''pret'' with the result.\r\n\r\n4. ''waitForProcess'' peeks into ''pret'' and then mutates ''ph'', changing it from an ''OpenHandle'' to a ''ClosedHandle''.\r\n\r\nThere is already a comment in the source code mentioning that this approach is unsafe:\r\n\r\n\r\n{{{\r\n -- don't hold the MVar while we call c_waitForProcess...\r\n -- (XXX but there's a small race window here during which another\r\n -- thread could close the handle or call waitForProcess)\r\n}}}\r\n\r\n, which is correct. However, it is also unsafe against asynchronous exceptions, and would remain so even if the ''MVar'' were held during the ''c_waitForProcess'' call. If an asynchronous exception occurs in between steps 3 and 4, then the system will be left in a state in which the child process has been successfully waited on by the OS, but the ''ProcessHandle'' is still in an ''OpenHandle'' state and the exit code has been lost. A subsequent call to ''waitForProcess'' will result in ''waitpid()'' unexpectedly returning ECHILD, or worse, the OS will have recycled the child process's PID and ''waitpid()'' will wait on the wrong process.\r\n\r\n''getProcessExitCode'' has the same bug.\r\n\r\nI propose fixing this by redefining ''ProcessHandle'' like so:\r\n\r\n{{{\r\ndata ProcessHandle = ProcessHandle PHANDLE (Ptr CInt) (MVar (Ptr CInt))\r\n}}}\r\n\r\n, where the second argument maybe points to the process's return code, and the third argument contains a pointer to a boolean flag indicating whether the second argument points to something meaningful. Extend the signature of ''c_waitForProcess'' to take both pointers. Then, let ''c_waitForProcess'' provide the following contract. If called as ''c_waitForProcess ph pret pflag'':\r\n\r\n1. ''*pflag'' is required to be false at the start of the call.\r\n\r\n2. If and only if the call to ''waitpid()'' returns successfully, then ''*pflag'' will be set to true and ''*pret'' will be populated with the exit code.\r\n\r\nThen, ''waitForProcess'' can behave as follows:\r\n\r\n1. The entire routine is wrapped in ''withMVar''. Asynchronous exceptions are allowed to occur.\r\n\r\n2. If ''*pflag'' is true, then construct an ''ExitCode'' from ''*pret'' and return it.\r\n\r\n3. Otherwise, call ''c_waitForProcess'' (with the same retry behavior as presently), and then construct and return an ''ExitCode'' after a successful return.\r\n\r\nAnd ''getProcessExitCode'' can:\r\n\r\n1. Mask exceptions.\r\n\r\n2. ''tryTakeMVar''. If the ''MVar'' is already held, unmask exceptions and return ''Nothing''.\r\n\r\n3. Peek at ''*pflag''.\r\n\r\n4. Replace the ''MVar''.\r\n\r\n5. Unmask exceptions.\r\n\r\n6. If ''*pflag'' is true, then construct and return an ''ExitCode'' from ''*pret''.\r\n\r\n7. Otherwise, return ''Nothing''.","type_of_failure":"OtherFailure","blocking":[]} -->Michael Snoymanmichael@snoyman.comMichael Snoymanmichael@snoyman.comhttps://gitlab.haskell.org/ghc/ghc/-/issues/7980runghc dies silently when given large numbers of arguments. Compiled code doe...2019-07-07T18:47:11Ztothermerunghc dies silently when given large numbers of arguments. Compiled code does not.I'm using ghc 7.6.2 on Ubuntu 13.04. To reproduce, put the following line in /tmp/test.hs
main = error "An Error message"
Then run the following commands at the shell:
gds\@lithium:/tmp$ runghc ./test.hs `seq 1 100000`
gds\@lithium:/t...I'm using ghc 7.6.2 on Ubuntu 13.04. To reproduce, put the following line in /tmp/test.hs
main = error "An Error message"
Then run the following commands at the shell:
gds\@lithium:/tmp$ runghc ./test.hs `seq 1 100000`
gds\@lithium:/tmp$ ghc -o test test.hs
gds\@lithium:/tmp$ ./test `seq 1 100000`
test: An Error message
gds\@lithium:/tmp$
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.2 |
| 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":"runghc dies silently when given large numbers of arguments. Compiled code does not.","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I'm using ghc 7.6.2 on Ubuntu 13.04. To reproduce, put the following line in /tmp/test.hs\r\n\r\nmain = error \"An Error message\"\r\n\r\nThen run the following commands at the shell:\r\n\r\ngds@lithium:/tmp$ runghc ./test.hs `seq 1 100000`\r\ngds@lithium:/tmp$ ghc -o test test.hs \r\ngds@lithium:/tmp$ ./test `seq 1 100000` \r\ntest: An Error message \r\ngds@lithium:/tmp$ \r\n\r\n ","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7971doesDirectoryExist description differs from its behavior2019-07-07T18:47:13ZdsfdoesDirectoryExist description differs from its behaviorThe documentation for doesDirectoryExist should read:
The operation 'doesDirectoryExist' returns 'True' if the argument file exists and is either a directory **or a symbolic link to a directory**, and 'False' otherwise.
<details><summa...The documentation for doesDirectoryExist should read:
The operation 'doesDirectoryExist' returns 'True' if the argument file exists and is either a directory **or a symbolic link to a directory**, and 'False' otherwise.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | libraries/directory |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"doesDirectoryExist description differs from its behavior","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":"The documentation for doesDirectoryExist should read:\r\n\r\nThe operation 'doesDirectoryExist' returns 'True' if the argument file exists and is either a directory '''or a symbolic link to a directory''', and 'False' otherwise.","type_of_failure":"OtherFailure","blocking":[]} -->Ben GamariBen Gamarihttps://gitlab.haskell.org/ghc/ghc/-/issues/7968fft2 benchmark sometimes fails (nofib)2019-07-07T18:47:14ZJan Stolarekjan.stolarek@ed.ac.ukfft2 benchmark sometimes fails (nofib)I noticed that sometimes `fft2` program in nofib benchmark suite returns values that are slightly different from expected (see error message at the end of this report). The most worrying for me is that it sometimes works properly and som...I noticed that sometimes `fft2` program in nofib benchmark suite returns values that are slightly different from expected (see error message at the end of this report). The most worrying for me is that it sometimes works properly and sometimes fails, as if the correctness of result depended on some random factor.
```
././fft2 512 < /dev/null
expected stdout not matched by reality
--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200
+++ /tmp/runtest10927.1 2013-06-04 18:06:08.401977002 +0200
@@ -1,3 +1,3 @@
-result1 = 2.59635799135966e-12
-result2 = 2.59635799135966e-12
-result3 = 4.8279900966008427e-8
+result1 = 2.6712796173433053e-12
+result2 = 2.6712796173433053e-12
+result3 = 4.827444399779779e-8
real 0m0.055s
user 0m0.049s
sys 0m0.005s
././fft2 512 < /dev/null
expected stdout not matched by reality
--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200
+++ /tmp/runtest10963.1 2013-06-04 18:06:08.507977002 +0200
@@ -1,3 +1,3 @@
-result1 = 2.59635799135966e-12
-result2 = 2.59635799135966e-12
-result3 = 4.8279900966008427e-8
+result1 = 2.6712796173433053e-12
+result2 = 2.6712796173433053e-12
+result3 = 4.827444399779779e-8
real 0m0.054s
user 0m0.047s
sys 0m0.005s
././fft2 512 < /dev/null
expected stdout not matched by reality
--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200
+++ /tmp/runtest10999.1 2013-06-04 18:06:08.602977002 +0200
@@ -1,3 +1,3 @@
-result1 = 2.59635799135966e-12
-result2 = 2.59635799135966e-12
-result3 = 4.8279900966008427e-8
+result1 = 2.6712796173433053e-12
+result2 = 2.6712796173433053e-12
+result3 = 4.827444399779779e-8
real 0m0.052s
user 0m0.044s
sys 0m0.007s
././fft2 512 < /dev/null
expected stdout not matched by reality
--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200
+++ /tmp/runtest11035.1 2013-06-04 18:06:08.712977002 +0200
@@ -1,3 +1,3 @@
-result1 = 2.59635799135966e-12
-result2 = 2.59635799135966e-12
-result3 = 4.8279900966008427e-8
+result1 = 2.6712796173433053e-12
+result2 = 2.6712796173433053e-12
+result3 = 4.827444399779779e-8
real 0m0.052s
user 0m0.046s
sys 0m0.006s
././fft2 512 < /dev/null
expected stdout not matched by reality
--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200
+++ /tmp/runtest11071.1 2013-06-04 18:06:08.816977002 +0200
@@ -1,3 +1,3 @@
-result1 = 2.59635799135966e-12
-result2 = 2.59635799135966e-12
-result3 = 4.8279900966008427e-8
+result1 = 2.6712796173433053e-12
+result2 = 2.6712796173433053e-12
+result3 = 4.827444399779779e-8
make[2]: *** [runtests] Błąd 1
Failed making all in fft2: 1
make[1]: *** [all] Błąd 1
Failed making all in spectral: 1
make: *** [all] Błąd 1
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------------- |
| Version | 7.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | NoFib benchmark suite |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"fft2 benchmark sometimes fails (nofib)","status":"New","operating_system":"","component":"NoFib benchmark suite","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"I noticed that sometimes `fft2` program in nofib benchmark suite returns values that are slightly different from expected (see error message at the end of this report). The most worrying for me is that it sometimes works properly and sometimes fails, as if the correctness of result depended on some random factor.\r\n\r\n{{{\r\n././fft2 512 < /dev/null\r\nexpected stdout not matched by reality\r\n--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200\r\n+++ /tmp/runtest10927.1 2013-06-04 18:06:08.401977002 +0200\r\n@@ -1,3 +1,3 @@\r\n-result1 = 2.59635799135966e-12\r\n-result2 = 2.59635799135966e-12\r\n-result3 = 4.8279900966008427e-8\r\n+result1 = 2.6712796173433053e-12\r\n+result2 = 2.6712796173433053e-12\r\n+result3 = 4.827444399779779e-8\r\n\r\nreal 0m0.055s\r\nuser 0m0.049s\r\nsys 0m0.005s\r\n././fft2 512 < /dev/null\r\nexpected stdout not matched by reality\r\n--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200\r\n+++ /tmp/runtest10963.1 2013-06-04 18:06:08.507977002 +0200\r\n@@ -1,3 +1,3 @@\r\n-result1 = 2.59635799135966e-12\r\n-result2 = 2.59635799135966e-12\r\n-result3 = 4.8279900966008427e-8\r\n+result1 = 2.6712796173433053e-12\r\n+result2 = 2.6712796173433053e-12\r\n+result3 = 4.827444399779779e-8\r\n\r\nreal 0m0.054s\r\nuser 0m0.047s\r\nsys 0m0.005s\r\n././fft2 512 < /dev/null\r\nexpected stdout not matched by reality\r\n--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200\r\n+++ /tmp/runtest10999.1 2013-06-04 18:06:08.602977002 +0200\r\n@@ -1,3 +1,3 @@\r\n-result1 = 2.59635799135966e-12\r\n-result2 = 2.59635799135966e-12\r\n-result3 = 4.8279900966008427e-8\r\n+result1 = 2.6712796173433053e-12\r\n+result2 = 2.6712796173433053e-12\r\n+result3 = 4.827444399779779e-8\r\n\r\nreal 0m0.052s\r\nuser 0m0.044s\r\nsys 0m0.007s\r\n././fft2 512 < /dev/null\r\nexpected stdout not matched by reality\r\n--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200\r\n+++ /tmp/runtest11035.1 2013-06-04 18:06:08.712977002 +0200\r\n@@ -1,3 +1,3 @@\r\n-result1 = 2.59635799135966e-12\r\n-result2 = 2.59635799135966e-12\r\n-result3 = 4.8279900966008427e-8\r\n+result1 = 2.6712796173433053e-12\r\n+result2 = 2.6712796173433053e-12\r\n+result3 = 4.827444399779779e-8\r\n\r\nreal 0m0.052s\r\nuser 0m0.046s\r\nsys 0m0.006s\r\n././fft2 512 < /dev/null\r\nexpected stdout not matched by reality\r\n--- fft2.stdout7 2013-05-15 08:01:24.014049002 +0200\r\n+++ /tmp/runtest11071.1 2013-06-04 18:06:08.816977002 +0200\r\n@@ -1,3 +1,3 @@\r\n-result1 = 2.59635799135966e-12\r\n-result2 = 2.59635799135966e-12\r\n-result3 = 4.8279900966008427e-8\r\n+result1 = 2.6712796173433053e-12\r\n+result2 = 2.6712796173433053e-12\r\n+result3 = 4.827444399779779e-8\r\nmake[2]: *** [runtests] Błąd 1\r\nFailed making all in fft2: 1\r\nmake[1]: *** [all] Błąd 1\r\nFailed making all in spectral: 1\r\nmake: *** [all] Błąd 1\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7934usleep hangs, no threads2019-07-07T18:47:23Zgelisamusleep hangs, no threadsimport System.Posix.Unistd
main = flip mapM_ \[0..\] $ \\i -\> do
usleep 100000
> print i
###
The above program hangs after a variable number of iterations (usually around 120, sometimes up to 200, often before the first call to pr...import System.Posix.Unistd
main = flip mapM_ \[0..\] $ \\i -\> do
usleep 100000
> print i
###
The above program hangs after a variable number of iterations (usually around 120, sometimes up to 200, often before the first call to print).
The documentation for usleep warns about bad interactions with threads, but the above program doesn't use any.
The problem also occurs with nanosleep, but not with threadDelay.
#1156 sounds related, but this time the problem also occurs without -threaded.
###
workaround: use threadDelay.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.4.2 |
| 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":"usleep hangs, no threads","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.4.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"import System.Posix.Unistd\r\nmain = flip mapM_ [0..] $ \\i -> do\r\n usleep 100000\r\n print i\r\n\r\n===\r\n\r\nThe above program hangs after a variable number of iterations (usually around 120, sometimes up to 200, often before the first call to print).\r\n\r\nThe documentation for usleep warns about bad interactions with threads, but the above program doesn't use any.\r\n\r\nThe problem also occurs with nanosleep, but not with threadDelay.\r\n\r\n#1156 sounds related, but this time the problem also occurs without -threaded.\r\n\r\n===\r\n\r\nworkaround: use threadDelay.\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7930Nested STM Invariants are lost2019-07-07T18:47:24ZRyan YatesNested STM Invariants are lostInvariants from a successful nested transaction should be merged with the parent.
```
import Control.Concurrent
import Control.Concurrent.STM
main = do
x <- atomically $
do a <- newTVar True
(always (readTVar a) ...Invariants from a successful nested transaction should be merged with the parent.
```
import Control.Concurrent
import Control.Concurrent.STM
main = do
x <- atomically $
do a <- newTVar True
(always (readTVar a) >> retry) `orElse` return ()
return a
atomically (writeTVar x False) -- Should not and does not fail
y <- atomically $
do a <- newTVar True
always (readTVar a) `orElse` return ()
return a
atomically (writeTVar y False) -- Should fail, but does not!
putStrLn "Ahhh!"
z <- atomically $
do a <- newTVar True
always (readTVar a)
return a
atomically (writeTVar z False) -- should and does fail
```
I know how to fix this. I'll have a patch with some tests and a fix soon.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.6.3 |
| 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":"Nested STM Invariants are lost","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"fryguybob"},"version":"7.6.3","keywords":["STM"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Invariants from a successful nested transaction should be merged with the parent.\r\n\r\n{{{\r\nimport Control.Concurrent\r\nimport Control.Concurrent.STM\r\n\r\nmain = do\r\n x <- atomically $\r\n do a <- newTVar True\r\n (always (readTVar a) >> retry) `orElse` return ()\r\n return a\r\n atomically (writeTVar x False) -- Should not and does not fail\r\n\r\n y <- atomically $\r\n do a <- newTVar True\r\n always (readTVar a) `orElse` return ()\r\n return a\r\n atomically (writeTVar y False) -- Should fail, but does not!\r\n\r\n putStrLn \"Ahhh!\"\r\n\r\n z <- atomically $\r\n do a <- newTVar True\r\n always (readTVar a)\r\n return a\r\n atomically (writeTVar z False) -- should and does fail\r\n}}}\r\n\r\nI know how to fix this. I'll have a patch with some tests and a fix soon.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Ryan YatesRyan Yateshttps://gitlab.haskell.org/ghc/ghc/-/issues/7910ConstraintKinds and reifyInstances2019-07-07T18:47:32ZtrevorConstraintKinds and reifyInstancesreifyInstances doesn't appear to know how to deal with a constraint that is just an alias. For example, the following prints (True,False):
```
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH...reifyInstances doesn't appear to know how to deal with a constraint that is just an alias. For example, the following prints (True,False):
```
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TemplateHaskell #-}
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
class C a
instance C Int
type D a = C a
main = print $(
do isCInst <- isInstance ''C [ConT ''Int]
isDInst <- isInstance ''D [ConT ''Int]
lift (isCInst,isDInst))
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.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":"ConstraintKinds and reifyInstances","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":["ConstraintKinds,","TemplateHaskell"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"reifyInstances doesn't appear to know how to deal with a constraint that is just an alias. For example, the following prints (True,False):\r\n\r\n\r\n{{{\r\n{-# LANGUAGE ConstraintKinds #-}\r\n{-# LANGUAGE TemplateHaskell #-}\r\n\r\nimport Language.Haskell.TH\r\nimport Language.Haskell.TH.Syntax\r\n\r\nclass C a\r\ninstance C Int\r\n\r\ntype D a = C a\r\n\r\nmain = print $(\r\n do isCInst <- isInstance ''C [ConT ''Int]\r\n isDInst <- isInstance ''D [ConT ''Int]\r\n lift (isCInst,isDInst))\r\n\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7899Strange behavior of -ddump-minimal-imports2019-07-07T18:47:37ZdsfStrange behavior of -ddump-minimal-importsThe following two line module:
```
import System.Exit
main = undefined >>= undefined
```
when compiled with `ghc -c -ddump-minimal-imports Test.hs` produces the following in Main.imports:
```
import System.Exit ( (>>=), undefined )
``...The following two line module:
```
import System.Exit
main = undefined >>= undefined
```
when compiled with `ghc -c -ddump-minimal-imports Test.hs` produces the following in Main.imports:
```
import System.Exit ( (>>=), undefined )
```
Those symbols are not exported by System.Exit.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.2 |
| 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":"Strange behavior of -ddump-minimal-imports","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The following two line module:\r\n\r\n{{{\r\nimport System.Exit\r\nmain = undefined >>= undefined\r\n}}}\r\n\r\nwhen compiled with {{{ghc -c -ddump-minimal-imports Test.hs}}} produces the following in Main.imports:\r\n{{{\r\nimport System.Exit ( (>>=), undefined )\r\n}}}\r\nThose symbols are not exported by System.Exit.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7877hSetBuffering002(ghci) and hSetBuffering004(ghci) fail on OS X2019-07-07T18:47:43ZnfrisbyhSetBuffering002(ghci) and hSetBuffering004(ghci) fail on OS X```
$ make TESTS="hSetBuffering002 hSetBuffering004"
# ... snip ...
Unexpected failures:
../../libraries/base/tests/IO hSetBuffering002 [bad exit code] (ghci)
../../libraries/base/tests/IO hSetBuffering004 [bad stdout or stderr] ...```
$ make TESTS="hSetBuffering002 hSetBuffering004"
# ... snip ...
Unexpected failures:
../../libraries/base/tests/IO hSetBuffering002 [bad exit code] (ghci)
../../libraries/base/tests/IO hSetBuffering004 [bad stdout or stderr] (ghci)
```
For 002, there's a stderror message: `<stdin>: hGetLine: illegal operation (handle is closed)`
For 004, it seems like ghci is trying to parse the part of the .genscript file that the program is supposed to use as stdin.
I'm on OS X 10.7.5
```
ghc : ade1ae97ed52c493ec415c1601dace39b64071dd
testsuite : 743cab5865ae0b9820dadc33a692511e0e467b9b
base : b3387abfbc94b69e977c232386acad4dde7597e8
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.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":"hSetBuffering002(ghci) and hSetBuffering004(ghci) fail on OS X","status":"New","operating_system":"","component":"GHCi","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"{{{\r\n$ make TESTS=\"hSetBuffering002 hSetBuffering004\"\r\n# ... snip ...\r\nUnexpected failures:\r\n ../../libraries/base/tests/IO hSetBuffering002 [bad exit code] (ghci)\r\n ../../libraries/base/tests/IO hSetBuffering004 [bad stdout or stderr] (ghci)\r\n}}}\r\n\r\nFor 002, there's a stderror message: `<stdin>: hGetLine: illegal operation (handle is closed)`\r\n\r\nFor 004, it seems like ghci is trying to parse the part of the .genscript file that the program is supposed to use as stdin.\r\n\r\nI'm on OS X 10.7.5\r\n\r\n{{{\r\nghc : ade1ae97ed52c493ec415c1601dace39b64071dd\r\ntestsuite : 743cab5865ae0b9820dadc33a692511e0e467b9b\r\nbase : b3387abfbc94b69e977c232386acad4dde7597e8\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7876hClose002 for ghci hangs on Mac OS X2019-07-07T18:47:43ZnfrisbyhClose002 for ghci hangs on Mac OS XI'm on OS X 10.7.5
```
ghc : ade1ae97ed52c493ec415c1601dace39b64071dd
testsuite : 743cab5865ae0b9820dadc33a692511e0e467b9b
base : b3387abfbc94b69e977c232386acad4dde7597e8
```
hClose002 fails with these three ways:
```
$ make TESTS=hCl...I'm on OS X 10.7.5
```
ghc : ade1ae97ed52c493ec415c1601dace39b64071dd
testsuite : 743cab5865ae0b9820dadc33a692511e0e467b9b
base : b3387abfbc94b69e977c232386acad4dde7597e8
```
hClose002 fails with these three ways:
```
$ make TESTS=hClose002
# ... snip ...
Unexpected failures:
../../libraries/base/tests/IO hClose002 [bad exit code] (ghci,threaded1,threaded2)
```
The test opens a file in !WriteMode, closes it "without telling the IO library", then hCloses it twice. Then it does that again in !ReadMode. Thus there are four hClose calls in total. It is the third one that hangs.https://gitlab.haskell.org/ghc/ghc/-/issues/7866floor (0/0) :: Int is different with -O0 and -O12019-07-07T18:47:45ZAlex Langfloor (0/0) :: Int is different with -O0 and -O1This program:
```
main = print (floor (0/0) :: Int)
```
prints a different result with -O0:
```
0
```
and -O1:
```
-9223372036854775808
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ----...This program:
```
main = print (floor (0/0) :: Int)
```
prints a different result with -O0:
```
0
```
and -O1:
```
-9223372036854775808
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.2 |
| 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":"floor (0/0) :: Int is different with -O0 and -O1","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"This program:\r\n{{{\r\nmain = print (floor (0/0) :: Int)\r\n}}}\r\n\r\nprints a different result with -O0:\r\n{{{\r\n0\r\n}}}\r\nand -O1:\r\n{{{\r\n-9223372036854775808\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7853UTF encodings do not detect overlong forms2019-07-07T18:47:48ZbatterseapowerUTF encodings do not detect overlong formsOverlong UTF-{8,16} sequences can have security implications (http://www.cl.cam.ac.uk/\~mgk25/unicode.html). Decoders for these encodings should detect them and flag them as invalid characters. GHC's implementations of these decoders do ...Overlong UTF-{8,16} sequences can have security implications (http://www.cl.cam.ac.uk/\~mgk25/unicode.html). Decoders for these encodings should detect them and flag them as invalid characters. GHC's implementations of these decoders do not do so!
This problem has additional implications for GHC since as we are not rejecting overlong sequences, trying to roundtrip 0xC0 0xB1 through UTF-8//ROUNDTRIP results in 0x31 rather than the expected sequence. The roundtripping fails because the overlong sequence is not flagged up by the UTF-8 encoder and so the surrogate escape mechanism never gets a chance to work.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.6.3 |
| 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":"UTF encodings do not detect overlong forms","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Overlong UTF-{8,16} sequences can have security implications (http://www.cl.cam.ac.uk/~mgk25/unicode.html). Decoders for these encodings should detect them and flag them as invalid characters. GHC's implementations of these decoders do not do so!\r\n\r\nThis problem has additional implications for GHC since as we are not rejecting overlong sequences, trying to roundtrip 0xC0 0xB1 through UTF-8//ROUNDTRIP results in 0x31 rather than the expected sequence. The roundtripping fails because the overlong sequence is not flagged up by the UTF-8 encoder and so the surrogate escape mechanism never gets a chance to work.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7839After forkIO'ing on Intel Mac, putStrLn (presumably) reports "hPutChar: faile...2019-07-07T18:47:52ZthorkilnaurAfter forkIO'ing on Intel Mac, putStrLn (presumably) reports "hPutChar: failed (Operation not supported)"Investigating #7715 on the tn23 builder, which is
```
$ uname -a
Darwin thorkil-naurs-intel-mac-mini.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386
$
```
I ran into:
```
...Investigating #7715 on the tn23 builder, which is
```
$ uname -a
Darwin thorkil-naurs-intel-mac-mini.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386
$
```
I ran into:
```
$ cat T7715O.hs
import Control.Monad
import Control.Concurrent
import System.IO
import System.Environment
main' c d2 = do
replicateM_ c $ forkIO $ do
putStrLn "Hello, world!"
threadDelay d2
mainArgsInterpret [cS,d2S] = main' (read cS) (read d2S)
main :: IO ()
main
= do
hSetBuffering stdout NoBuffering
hSetBuffering stderr NoBuffering
args <- getArgs
mainArgsInterpret args
$ /Users/thorkilnaur/tn/builders/GHCBuilder/tn23/builder/tempbuild/build/inplace/bin/ghc-stage2 --make T7715O.hs -threaded -debug -rtsopts
[1 of 1] Compiling Main ( T7715O.hs, T7715O.o )
Linking T7715O ...
$ ./T7715O 25 10000000
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
HeT7715O: <stdout>: hPutChar: failed (Operation not supported)
T7715O: <stdout>: hPutChar: failed (Operation not supported)
$
```
This doesn't happen on
```
$ uname -a
Linux tn24 3.2.0-39-generic #62-Ubuntu SMP Wed Feb 27 22:05:17 UTC 2013 i686 i686 i386 GNU/Linux
$
```
Best regards
Thorkil
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.7 |
| 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":"After forkIO'ing on Intel Mac, putStrLn (presumably) reports \"hPutChar: failed (Operation not supported)\"","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Investigating #7715 on the tn23 builder, which is\r\n{{{\r\n$ uname -a\r\nDarwin thorkil-naurs-intel-mac-mini.local 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386\r\n$ \r\n}}}\r\nI ran into:\r\n{{{\r\n$ cat T7715O.hs \r\nimport Control.Monad\r\nimport Control.Concurrent\r\nimport System.IO\r\nimport System.Environment\r\n\r\nmain' c d2 = do\r\n replicateM_ c $ forkIO $ do\r\n putStrLn \"Hello, world!\"\r\n threadDelay d2\r\n\r\nmainArgsInterpret [cS,d2S] = main' (read cS) (read d2S)\r\n\r\nmain :: IO ()\r\nmain\r\n = do\r\n hSetBuffering stdout NoBuffering\r\n hSetBuffering stderr NoBuffering\r\n args <- getArgs\r\n mainArgsInterpret args\r\n$ /Users/thorkilnaur/tn/builders/GHCBuilder/tn23/builder/tempbuild/build/inplace/bin/ghc-stage2 --make T7715O.hs -threaded -debug -rtsopts \r\n[1 of 1] Compiling Main ( T7715O.hs, T7715O.o )\r\nLinking T7715O ...\r\n$ ./T7715O 25 10000000 \r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHello, world!\r\nHeT7715O: <stdout>: hPutChar: failed (Operation not supported)\r\nT7715O: <stdout>: hPutChar: failed (Operation not supported)\r\n$\r\n}}}\r\nThis doesn't happen on\r\n{{{\r\n$ uname -a\r\nLinux tn24 3.2.0-39-generic #62-Ubuntu SMP Wed Feb 27 22:05:17 UTC 2013 i686 i686 i386 GNU/Linux\r\n$ \r\n}}}\r\nBest regards\r\nThorkil\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/7815STM fails to validate read.2020-01-29T16:18:56ZRyan YatesSTM fails to validate read.This issue was brought up by napping in `#haskell` with this paste:
[http://hpaste.org/85134](http://hpaste.org/85134) (the first paste in particular)
The code is:
```
import Control.Concurrent.STM
import Control.Concurrent
import Con...This issue was brought up by napping in `#haskell` with this paste:
[http://hpaste.org/85134](http://hpaste.org/85134) (the first paste in particular)
The code is:
```
import Control.Concurrent.STM
import Control.Concurrent
import Control.Monad
main = do
dog <- newTVarIO False
cat <- newTVarIO False
let unset = do
d <- readTVar dog
c <- readTVar cat
if (d || c) then retry else return ()
setDog = unset >> writeTVar dog True
setCat = unset >> writeTVar cat True
oops = do
d <- readTVar dog
c <- readTVar cat
guard (d && c)
reset = do
writeTVar dog False
writeTVar cat False
reset' = do
d <- readTVar dog
c <- readTVar cat
guard (d || c)
reset
forkIO (atomically oops >> putStrLn "Oh Noes!")
forever (do
forkIO (atomically setDog)
forkIO (atomically setCat)
atomically reset'
atomically reset')
```
When run it produces:
```
$ ghc --make test.hs -threaded -rtsopts
$ ./test +RTS -N2
Oh Noes!
test: thread blocked indefinitely in an STM transaction
```
The second message is just a consequence of entering an unexpected state. The first message indicates that both the transactions `cat` and `dog` committed at the same time.
It does this for HEAD and 7.6.
I've sketched out an interleaving that leads to this. TRec entries
are in the first and third column and TVar's are in the second column. Each entry has a TVar name and the expected value followed
by the new value and then a number of updates if it has been read. TVars list their value and their number of updates.
```
A TRec TVar B TRec
-- Transactions start
cat F F cat F 0 cat F F -- Initial reads.
dog F F dog F 0 dog F F
cat F T dog F T -- Local writes in TRec's
-- Validation:
cat F F 0 -- B reads num_updates from cat (with
^ -- consistency check with value)
cat F T cat A 0 | -- A acquires lock for cat (atomic cas)
dog F F 0 ^ | -- A reads num_updates from dog (with
^ | | -- consistency check with value)
| dog B 0 dog F T | -- B acquires lock for dog (atomic cas)
| | ^ |
| | | |
Success 0 | 0 | -- read check for A
Success 0 0 -- read check for B
cat A 1 -- Increment version
cat T 1 -- Unlock with new value
dog B 1 -- Increment version
dog B T -- Unlock with new value
```
What is clear here is that the version number is not enough to check
in `check_read_only` because there is a gap between locking and
incrementing the version. We need to know atomically that the TVar is not locked and it's version number is the same.
I need to read through the right parts of Keir Fraser's thesis carefully, but it seems like the read phase here is only helpful in preventing a commit that writes back the exact value we have already seen while we are in the middle of committing.
The code for `check_read_only` is here:
```c
static StgBool check_read_only(StgTRecHeader *trec STG_UNUSED) {
StgBool result = TRUE;
ASSERT (config_use_read_phase);
IF_STM_FG_LOCKS({
FOR_EACH_ENTRY(trec, e, {
StgTVar *s;
s = e -> tvar;
if (entry_is_read_only(e)) {
TRACE("%p : check_read_only for TVar %p, saw %ld", trec, s, e -> num_updates);
if (s -> num_updates != e -> num_updates) {
// ||s -> current_value != e -> expected_value) {
TRACE("%p : mismatch", trec);
result = FALSE;
BREAK_FOR_EACH;
}
}
});
});
return result;
}
```
If I restore the commented out line (which appears commented out in the first commit of this code that I can find) I can't reproduce the issue, but I think there is still a problem due to the ordering of
those checks: we could observe the version as the same, while it
is locked, have the TVar unlock, then observe the value the same.
Switching the order we can only observe the TVar unlocked if the
update has been incremented (as long as we are on an architecture
that ensures this such as x86).
Does this seem right? One issue is that given the interleaving that above with this added check *both* transactions could fail to commit. I think the algorithms from Fraser avoid this, but I think it always involves invalidating another transaction (i.e. killing off any other transactions observed to be in the read check phase with an overlapping TVar in a way that results in only one winner (see page 21 section 4.4 in *Concurrent Programming Without Locks*)).
As a side note, the issue can be avoided by ensuring that the reads become writes and avoiding the read only check. But you can only
become a write if the values do not have matching pointers, switching to Ints instead of Bools gets you there.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.7 |
| 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":"STM fails to validate read.","status":"New","operating_system":"","component":"Runtime System","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":["STM"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"This issue was brought up by napping in {{{#haskell}}} with this paste:\r\n\r\n[http://hpaste.org/85134] (the first paste in particular)\r\n\r\nThe code is:\r\n\r\n{{{\r\nimport Control.Concurrent.STM\r\nimport Control.Concurrent\r\nimport Control.Monad\r\n\r\nmain = do\r\n dog <- newTVarIO False\r\n cat <- newTVarIO False\r\n let unset = do\r\n d <- readTVar dog\r\n c <- readTVar cat\r\n if (d || c) then retry else return ()\r\n setDog = unset >> writeTVar dog True\r\n setCat = unset >> writeTVar cat True\r\n oops = do\r\n d <- readTVar dog\r\n c <- readTVar cat\r\n guard (d && c)\r\n reset = do\r\n writeTVar dog False\r\n writeTVar cat False\r\n reset' = do\r\n d <- readTVar dog\r\n c <- readTVar cat\r\n guard (d || c)\r\n reset\r\n\r\n forkIO (atomically oops >> putStrLn \"Oh Noes!\")\r\n forever (do\r\n forkIO (atomically setDog)\r\n forkIO (atomically setCat)\r\n atomically reset'\r\n atomically reset')\r\n}}}\r\n\r\nWhen run it produces:\r\n\r\n{{{\r\n$ ghc --make test.hs -threaded -rtsopts\r\n$ ./test +RTS -N2\r\nOh Noes!\r\ntest: thread blocked indefinitely in an STM transaction\r\n}}}\r\n\r\nThe second message is just a consequence of entering an unexpected state. The first message indicates that both the transactions {{{cat}}} and {{{dog}}} committed at the same time.\r\n\r\nIt does this for HEAD and 7.6.\r\n\r\nI've sketched out an interleaving that leads to this. TRec entries\r\nare in the first and third column and TVar's are in the second column. Each entry has a TVar name and the expected value followed\r\nby the new value and then a number of updates if it has been read. TVars list their value and their number of updates.\r\n\r\n{{{\r\n A TRec TVar B TRec\r\n -- Transactions start\r\ncat F F cat F 0 cat F F -- Initial reads.\r\ndog F F dog F 0 dog F F \r\n\r\ncat F T dog F T -- Local writes in TRec's\r\n \r\n -- Validation:\r\n\r\n cat F F 0 -- B reads num_updates from cat (with\r\n ^ -- consistency check with value)\r\ncat F T cat A 0 | -- A acquires lock for cat (atomic cas)\r\ndog F F 0 ^ | -- A reads num_updates from dog (with\r\n ^ | | -- consistency check with value)\r\n | dog B 0 dog F T | -- B acquires lock for dog (atomic cas)\r\n | | ^ | \r\n | | | |\r\nSuccess 0 | 0 | -- read check for A\r\nSuccess 0 0 -- read check for B\r\n\r\n cat A 1 -- Increment version\r\n cat T 1 -- Unlock with new value\r\n dog B 1 -- Increment version\r\n dog B T -- Unlock with new value\r\n}}}\r\n\r\nWhat is clear here is that the version number is not enough to check\r\nin {{{check_read_only}}} because there is a gap between locking and \r\nincrementing the version. We need to know atomically that the TVar is not locked and it's version number is the same.\r\n\r\nI need to read through the right parts of Keir Fraser's thesis carefully, but it seems like the read phase here is only helpful in preventing a commit that writes back the exact value we have already seen while we are in the middle of committing. \r\n\r\nThe code for {{{check_read_only}}} is here:\r\n\r\n{{{\r\n#!c\r\nstatic StgBool check_read_only(StgTRecHeader *trec STG_UNUSED) {\r\n StgBool result = TRUE;\r\n\r\n ASSERT (config_use_read_phase);\r\n IF_STM_FG_LOCKS({\r\n FOR_EACH_ENTRY(trec, e, {\r\n StgTVar *s;\r\n s = e -> tvar;\r\n if (entry_is_read_only(e)) {\r\n TRACE(\"%p : check_read_only for TVar %p, saw %ld\", trec, s, e -> num_updates);\r\n if (s -> num_updates != e -> num_updates) {\r\n // ||s -> current_value != e -> expected_value) {\r\n TRACE(\"%p : mismatch\", trec);\r\n result = FALSE;\r\n BREAK_FOR_EACH;\r\n }\r\n }\r\n });\r\n });\r\n\r\n return result;\r\n}\r\n}}}\r\n\r\nIf I restore the commented out line (which appears commented out in the first commit of this code that I can find) I can't reproduce the issue, but I think there is still a problem due to the ordering of\r\nthose checks: we could observe the version as the same, while it \r\nis locked, have the TVar unlock, then observe the value the same. \r\n\r\nSwitching the order we can only observe the TVar unlocked if the\r\nupdate has been incremented (as long as we are on an architecture\r\nthat ensures this such as x86).\r\n\r\nDoes this seem right? One issue is that given the interleaving that above with this added check ''both'' transactions could fail to commit. I think the algorithms from Fraser avoid this, but I think it always involves invalidating another transaction (i.e. killing off any other transactions observed to be in the read check phase with an overlapping TVar in a way that results in only one winner (see page 21 section 4.4 in ''Concurrent Programming Without Locks'')).\r\n\r\nAs a side note, the issue can be avoided by ensuring that the reads become writes and avoiding the read only check. But you can only \r\nbecome a write if the values do not have matching pointers, switching to Ints instead of Bools gets you there.","type_of_failure":"OtherFailure","blocking":[]} -->7.8.1Ian Lynagh <igloo@earth.li>Ian Lynagh <igloo@earth.li>https://gitlab.haskell.org/ghc/ghc/-/issues/7788Recursive type family causes <<loop>>2019-07-07T18:48:09ZshachafRecursive type family causes <<loop>>This file:
```
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
data Proxy a = Proxy
foo :: Proxy (F (Fix Id)) -> ()
foo = undefined
newtype Fix a = Fix (a (Fix a))
newtype Id a = Id a
type family F a
type instanc...This file:
```
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
data Proxy a = Proxy
foo :: Proxy (F (Fix Id)) -> ()
foo = undefined
newtype Fix a = Fix (a (Fix a))
newtype Id a = Id a
type family F a
type instance F (Fix a) = F (a (Fix a))
type instance F (Id a) = F a
main :: IO ()
main = print $ foo Proxy
```
Dies with `<<loop>>`. The type family is recursive, of course:
```
*Main> :kind! F (Fix Id)
F (Fix Id) :: *^CInterrupted.
```
But `<<loop>>` is still not the behavior I'd expect. The actual value is just `undefined`.
In the file that this example came up, the situation was even worse -- there was a situation where
```
moldMapOf l f = runAccessor . l (Accessor . f)
main = print $ (flip appEndo [] . moldMapOf (ix 3) (Endo . (:)) $ testVal :: [Int]) -- <<loop>>
main = print $ (flip appEndo [] . runAccessor . (ix 3) (Accessor . Endo . (:)) $ testVal :: [Int]) -- undefined
```
I.e. substitution can turn one program (which happens to be ⊥ here, admittedly, but that's not fundamental) into another (`<<loop>>`). This makes it very tricky to track down the recursive type family. If necessary I can hunt down a working test case and post it here -- it's a bit tricky to get working, though.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.6.2 |
| 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":"Recursive type family causes <<loop>>","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"This file:\r\n\r\n{{{\r\n{-# LANGUAGE TypeFamilies #-}\r\n{-# LANGUAGE UndecidableInstances #-}\r\n\r\ndata Proxy a = Proxy\r\n\r\nfoo :: Proxy (F (Fix Id)) -> ()\r\nfoo = undefined\r\n\r\nnewtype Fix a = Fix (a (Fix a))\r\nnewtype Id a = Id a\r\n\r\ntype family F a\r\ntype instance F (Fix a) = F (a (Fix a))\r\ntype instance F (Id a) = F a\r\n\r\nmain :: IO ()\r\nmain = print $ foo Proxy\r\n}}}\r\n\r\nDies with `<<loop>>`. The type family is recursive, of course:\r\n\r\n{{{\r\n*Main> :kind! F (Fix Id)\r\nF (Fix Id) :: *^CInterrupted.\r\n}}}\r\n\r\nBut `<<loop>>` is still not the behavior I'd expect. The actual value is just `undefined`.\r\n\r\nIn the file that this example came up, the situation was even worse -- there was a situation where\r\n\r\n{{{\r\nmoldMapOf l f = runAccessor . l (Accessor . f)\r\nmain = print $ (flip appEndo [] . moldMapOf (ix 3) (Endo . (:)) $ testVal :: [Int]) -- <<loop>>\r\nmain = print $ (flip appEndo [] . runAccessor . (ix 3) (Accessor . Endo . (:)) $ testVal :: [Int]) -- undefined\r\n}}}\r\n\r\nI.e. substitution can turn one program (which happens to be ⊥ here, admittedly, but that's not fundamental) into another (`<<loop>>`). This makes it very tricky to track down the recursive type family. If necessary I can hunt down a working test case and post it here -- it's a bit tricky to get working, though.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Richard Eisenbergrae@richarde.devRichard Eisenbergrae@richarde.devhttps://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 Marlow