GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2019-07-07T18:47:07Zhttps://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/8285unexpected behavior with encodeFloat on large inputs2019-07-07T18:45:43ZCarter Schonwaldunexpected behavior with encodeFloat on large inputs```
> encodeFloat 1 1023
8.98846567431158e307 -- ok
> encodeFloat 1 1024
Infinity -- ok
> encodeFloat 1 (2^31 - 1)
Infinity -- ok
> encodeFloat 1 (2^31)
0.0 -- not ok
``````
> encodeFloat 1 1023
8.98846567431158e307 -- ok
> encodeFloat 1 1024
Infinity -- ok
> encodeFloat 1 (2^31 - 1)
Infinity -- ok
> encodeFloat 1 (2^31)
0.0 -- not ok
```8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/8293user001 spuriously fails if getGroupEntryForID correctly fails2019-07-07T18:45:41ZEdward Z. Yanguser001 spuriously fails if getGroupEntryForID correctly failsIn some cases, a user's current group ID can be a number for a non-existent group. While this usually indicates the system is misconfigured in some way, it can also occur inside chroots or other environments where the information in /etc...In some cases, a user's current group ID can be a number for a non-existent group. While this usually indicates the system is misconfigured in some way, it can also occur inside chroots or other environments where the information in /etc/groups is not to be considered reliable. Unfortunately, the user001 has no way of telling that the failure is proper, and fails the test anyway. We ought to do something more robust.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.7 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | lowest |
| Resolution | Unresolved |
| Component | libraries/unix |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"user001 spuriously fails if getGroupEntryForID correctly fails","status":"New","operating_system":"","component":"libraries/unix","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.7","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"In some cases, a user's current group ID can be a number for a non-existent group. While this usually indicates the system is misconfigured in some way, it can also occur inside chroots or other environments where the information in /etc/groups is not to be considered reliable. Unfortunately, the user001 has no way of telling that the failure is proper, and fails the test anyway. We ought to do something more robust.","type_of_failure":"OtherFailure","blocking":[]} -->Edward KmettEdward Kmetthttps://gitlab.haskell.org/ghc/ghc/-/issues/8362Filesystem related tests failed on solaris (SmartOS)2019-07-07T18:45:23ZlerouxFilesystem related tests failed on solaris (SmartOS)Getting filesystem (files/permissions) related test faiures on SmartOS (32bit).
```
$ uname -a
SunOS pkgx86 5.11 joyent_20130919T215407Z i86pc i386 i86pc Solaris
```
Unexpected failures: `TEST="openFile003 getPermissions001 processGrou...Getting filesystem (files/permissions) related test faiures on SmartOS (32bit).
```
$ uname -a
SunOS pkgx86 5.11 joyent_20130919T215407Z i86pc i386 i86pc Solaris
```
Unexpected failures: `TEST="openFile003 getPermissions001 processGroup002 user001 posix005"`
The testsuite output is attached.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | 7.6.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | high |
| Resolution | Unresolved |
| Component | libraries (other) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Filesystem related tests failed on solaris (SmartOS)","status":"New","operating_system":"","component":"libraries (other)","related":[],"milestone":"7.8.3","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Getting filesystem (files/permissions) related test faiures on SmartOS (32bit).\r\n\r\n{{{\r\n$ uname -a\r\nSunOS pkgx86 5.11 joyent_20130919T215407Z i86pc i386 i86pc Solaris\r\n}}}\r\n\r\nUnexpected failures: `TEST=\"openFile003 getPermissions001 processGroup002 user001 posix005\"`\r\n\r\nThe testsuite output is attached.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/9307LLVM vs NCG: floating point numbers close to zero have different sign2019-07-07T18:40:56Zjrp2014LLVM vs NCG: floating point numbers close to zero have different signCompiling HEAD with perf-llvm, (3.4.2) and running the nofib suite fails at the wave4main case. It is not clear to me whether wave4main should always produce the same output (and so the test fails because it does not do so) or whether th...Compiling HEAD with perf-llvm, (3.4.2) and running the nofib suite fails at the wave4main case. It is not clear to me whether wave4main should always produce the same output (and so the test fails because it does not do so) or whether the numbers generated depend on some feature of the build settings, or OS.
```
HC = /Users/xxx/Projects/ghc/inplace/bin/ghc-stage2
HC_OPTS = -O2 -Rghc-timing -H32m -hisuf hi -cpp -fglasgow-exts -rtsopts
RUNTEST_OPTS = -ghc-timing
==nofib== wave4main: size of wave4main follows...
__TEXT __DATA __OBJC others dec hex
4091904 450560 0 4295947176 4300489640 1005443a8
==nofib== wave4main: time to run wave4main follows...
../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000;
real 0m0.217s
user 0m0.191s
sys 0m0.011s
././wave4main 4000 < /dev/null
expected stdout not matched by reality
--- wave4main.stdout 2014-07-08 20:57:14.000000000 +0100
+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest16932.1 2014-07-13 13:43:22.000000000 +0100
@@ -1 +1 @@
-69923/1465
+69096/1465
real 0m0.197s
user 0m0.186s
sys 0m0.008s
././wave4main 4000 < /dev/null
expected stdout not matched by reality
--- wave4main.stdout 2014-07-08 20:57:14.000000000 +0100
+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest16961.1 2014-07-13 13:43:22.000000000 +0100
@@ -1 +1 @@
-69923/1465
+69096/1465
real 0m0.201s
user 0m0.189s
sys 0m0.009s
././wave4main 4000 < /dev/null
expected stdout not matched by reality
--- wave4main.stdout 2014-07-08 20:57:14.000000000 +0100
+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17011.1 2014-07-13 13:43:22.000000000 +0100
@@ -1 +1 @@
-69923/1465
+69096/1465
real 0m0.201s
user 0m0.190s
sys 0m0.008s
././wave4main 4000 < /dev/null
expected stdout not matched by reality
--- wave4main.stdout 2014-07-08 20:57:14.000000000 +0100
+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17051.1 2014-07-13 13:43:23.000000000 +0100
@@ -1 +1 @@
-69923/1465
+69096/1465
real 0m0.200s
user 0m0.189s
sys 0m0.009s
././wave4main 4000 < /dev/null
expected stdout not matched by reality
--- wave4main.stdout 2014-07-08 20:57:14.000000000 +0100
+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17080.1 2014-07-13 13:43:23.000000000 +0100
@@ -1 +1 @@
-69923/1465
+69096/1465
make: *** [runtests] Error 1
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | --------------------- |
| Version | 7.8.3 |
| 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":"wave4main in nofib fails","status":"New","operating_system":"","component":"NoFib benchmark suite","related":[],"milestone":"7.10.1","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":["wave4main"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"\r\nCompiling HEAD with perf-llvm, (3.4.2) and running the nofib suite fails at the wave4main case. It is not clear to me whether wave4main should always produce the same output (and so the test fails because it does not do so) or whether the numbers generated depend on some feature of the build settings, or OS.\r\n\r\n\r\n{{{\r\nHC = /Users/xxx/Projects/ghc/inplace/bin/ghc-stage2\r\nHC_OPTS = -O2 -Rghc-timing -H32m -hisuf hi -cpp -fglasgow-exts -rtsopts\r\nRUNTEST_OPTS = -ghc-timing\r\n==nofib== wave4main: size of wave4main follows...\r\n__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\r\n4091904\t450560\t0\t4295947176\t4300489640\t1005443a8\r\n==nofib== wave4main: time to run wave4main follows...\r\n../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000; ../../../runstdtest/runstdtest ./wave4main -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -o1 wave4main.stdout -o1 wave4main.stdout2 -o1 wave4main.stdout3 -ghc-timing 4000;\r\n\r\nreal\t0m0.217s\r\nuser\t0m0.191s\r\nsys\t0m0.011s\r\n././wave4main 4000 < /dev/null\r\nexpected stdout not matched by reality\r\n--- wave4main.stdout\t2014-07-08 20:57:14.000000000 +0100\r\n+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest16932.1\t2014-07-13 13:43:22.000000000 +0100\r\n@@ -1 +1 @@\r\n-69923/1465\r\n+69096/1465\r\n\r\nreal\t0m0.197s\r\nuser\t0m0.186s\r\nsys\t0m0.008s\r\n././wave4main 4000 < /dev/null\r\nexpected stdout not matched by reality\r\n--- wave4main.stdout\t2014-07-08 20:57:14.000000000 +0100\r\n+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest16961.1\t2014-07-13 13:43:22.000000000 +0100\r\n@@ -1 +1 @@\r\n-69923/1465\r\n+69096/1465\r\n\r\nreal\t0m0.201s\r\nuser\t0m0.189s\r\nsys\t0m0.009s\r\n././wave4main 4000 < /dev/null\r\nexpected stdout not matched by reality\r\n--- wave4main.stdout\t2014-07-08 20:57:14.000000000 +0100\r\n+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17011.1\t2014-07-13 13:43:22.000000000 +0100\r\n@@ -1 +1 @@\r\n-69923/1465\r\n+69096/1465\r\n\r\nreal\t0m0.201s\r\nuser\t0m0.190s\r\nsys\t0m0.008s\r\n././wave4main 4000 < /dev/null\r\nexpected stdout not matched by reality\r\n--- wave4main.stdout\t2014-07-08 20:57:14.000000000 +0100\r\n+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17051.1\t2014-07-13 13:43:23.000000000 +0100\r\n@@ -1 +1 @@\r\n-69923/1465\r\n+69096/1465\r\n\r\nreal\t0m0.200s\r\nuser\t0m0.189s\r\nsys\t0m0.009s\r\n././wave4main 4000 < /dev/null\r\nexpected stdout not matched by reality\r\n--- wave4main.stdout\t2014-07-08 20:57:14.000000000 +0100\r\n+++ /var/folders/d9/94xh7l810mz3_skcsfh68khh0000gn/T//runtest17080.1\t2014-07-13 13:43:23.000000000 +0100\r\n@@ -1 +1 @@\r\n-69923/1465\r\n+69096/1465\r\nmake: *** [runtests] Error 1\r\n\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1https://gitlab.haskell.org/ghc/ghc/-/issues/9347forkProcess does not acquire global handle locks2019-07-07T18:40:47Zedsko@edsko.netforkProcess does not acquire global handle locksThe global I/O handles (`stdout`, `stdin`, `stderr`) all make use an `MVar` wrapping a `Handle__`, and many I/O functions temporarily take this `MVar` (for instance, functions such as `hPutStr` include a call to `wantWritableHandle`, whi...The global I/O handles (`stdout`, `stdin`, `stderr`) all make use an `MVar` wrapping a `Handle__`, and many I/O functions temporarily take this `MVar` (for instance, functions such as `hPutStr` include a call to `wantWritableHandle`, which uses `withHandle_'`, which involves taking the `MVar`, executing some operation, and then putting the `MVar` back).
Suppose we have a program consisting of two threads A and B, where thread A is doing I/O. If thread B does a call to `forkProcess` then it is possible that the `fork()` happens at the point that A has just taken, say, the `MVar` for `stdout`. If this happens, every use of `stdout` in the child process will now forever deadlock.
This is not a theoretical scenario. The example code reported by Michael Snoyman a few years ago
http://www.haskell.org/pipermail/haskell-cafe/2012-October/103922.html
exhibits precisely this behaviour: the child process deadlocks (not all the the time, but very frequently), exactly because of this problem.
In `forkProcess` we avoid this sort of situation for all of the global RTS locks by acquiring the lock just before the call to `fork()`, and then releasing the lock in the parent again and re-initializing the lock in the child. But there are no provisions for Haskell-land locks such as the above `MVar`.
In principle we can work around this problem entirely in user-land. Here is a modified version of Michael's code that does not deadlock (at least, it never has in my tests..), that basically takes the same acquire-release\*2 trick that `forkProcess` does for RTS locks in the lines marked `(*)`:
```
import System.Posix.Process (forkProcess, getProcessID)
import Control.Concurrent (forkIO, threadDelay)
import System.IO (hFlush, stdout)
import System.Posix.Signals (signalProcess, sigKILL)
import Control.Exception (finally)
import Control.Concurrent
import GHC.IO.Handle.Types
import System.IO
main :: IO ()
main = do
mapM_ spawnChild [1..9]
ioLock <- lockIO -- (*)
child <- forkProcess $ do
unlockIO ioLock -- (*)
putStrLn "starting child"
hFlush stdout
loop "child" 0
unlockIO ioLock -- (*)
print ("child pid", child)
hFlush stdout
-- I've commented out the "finally" so that the zombie process stays alive,
-- to prove that it was actually created.
loop "parent" 0 -- `finally` signalProcess sigKILL child
spawnChild :: Int -> IO ()
spawnChild i = do
_ <- forkIO $ loop ("spawnChild " ++ show i) 0
return ()
loop :: String -> Int -> IO ()
loop msg i = do
pid <- getProcessID
print (pid, msg, i)
hFlush stdout
threadDelay 1000000
loop msg (i + 1)
--------------------------------------------------------------------------------
lockIO :: IO Handle__
lockIO =
case stdout of
FileHandle _ m -> takeMVar m
unlockIO :: Handle__ -> IO ()
unlockIO hout =
case stdout of
FileHandle _ m -> putMVar m hout
```
I guess that _any_ global `MVar` or `TVar` is suspect when using `forkProcess`.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.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":"forkProcess does not acquire global handle locks","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.2","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"The global I/O handles (`stdout`, `stdin`, `stderr`) all make use an `MVar` wrapping a `Handle__`, and many I/O functions temporarily take this `MVar` (for instance, functions such as `hPutStr` include a call to `wantWritableHandle`, which uses `withHandle_'`, which involves taking the `MVar`, executing some operation, and then putting the `MVar` back).\r\n\r\nSuppose we have a program consisting of two threads A and B, where thread A is doing I/O. If thread B does a call to `forkProcess` then it is possible that the `fork()` happens at the point that A has just taken, say, the `MVar` for `stdout`. If this happens, every use of `stdout` in the child process will now forever deadlock. \r\n\r\nThis is not a theoretical scenario. The example code reported by Michael Snoyman a few years ago\r\n\r\nhttp://www.haskell.org/pipermail/haskell-cafe/2012-October/103922.html\r\n\r\nexhibits precisely this behaviour: the child process deadlocks (not all the the time, but very frequently), exactly because of this problem. \r\n\r\nIn `forkProcess` we avoid this sort of situation for all of the global RTS locks by acquiring the lock just before the call to `fork()`, and then releasing the lock in the parent again and re-initializing the lock in the child. But there are no provisions for Haskell-land locks such as the above `MVar`.\r\n\r\nIn principle we can work around this problem entirely in user-land. Here is a modified version of Michael's code that does not deadlock (at least, it never has in my tests..), that basically takes the same acquire-release*2 trick that `forkProcess` does for RTS locks in the lines marked `(*)`:\r\n\r\n{{{\r\nimport System.Posix.Process (forkProcess, getProcessID)\r\nimport Control.Concurrent (forkIO, threadDelay)\r\nimport System.IO (hFlush, stdout)\r\nimport System.Posix.Signals (signalProcess, sigKILL)\r\nimport Control.Exception (finally)\r\n\r\nimport Control.Concurrent\r\nimport GHC.IO.Handle.Types\r\nimport System.IO\r\n\r\nmain :: IO ()\r\nmain = do\r\n mapM_ spawnChild [1..9]\r\n\r\n ioLock <- lockIO -- (*)\r\n child <- forkProcess $ do\r\n unlockIO ioLock -- (*)\r\n putStrLn \"starting child\"\r\n hFlush stdout\r\n loop \"child\" 0\r\n unlockIO ioLock -- (*)\r\n\r\n print (\"child pid\", child)\r\n hFlush stdout\r\n\r\n -- I've commented out the \"finally\" so that the zombie process stays alive,\r\n -- to prove that it was actually created.\r\n loop \"parent\" 0 -- `finally` signalProcess sigKILL child\r\n\r\nspawnChild :: Int -> IO ()\r\nspawnChild i = do\r\n _ <- forkIO $ loop (\"spawnChild \" ++ show i) 0\r\n return ()\r\n\r\nloop :: String -> Int -> IO ()\r\nloop msg i = do\r\n pid <- getProcessID\r\n print (pid, msg, i)\r\n hFlush stdout\r\n threadDelay 1000000\r\n loop msg (i + 1)\r\n\r\n--------------------------------------------------------------------------------\r\n\r\nlockIO :: IO Handle__ \r\nlockIO = \r\n case stdout of\r\n FileHandle _ m -> takeMVar m \r\n\r\nunlockIO :: Handle__ -> IO ()\r\nunlockIO hout = \r\n case stdout of\r\n FileHandle _ m -> putMVar m hout\r\n}}}\r\n\r\nI guess that _any_ global `MVar` or `TVar` is suspect when using `forkProcess`. ","type_of_failure":"OtherFailure","blocking":[]} -->Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/9406unexpected failure for T7837(profasm)2019-07-07T18:40:31Zjrp2014unexpected failure for T7837(profasm)This may be a test suite configuration error as the normal case works (and indeed I get a lot of profiled case failures of other cases). When run with an llvm-perf build of the HEAD, I get:
```
=====> T7837(normal) 1395 of 4068 [0, 0, 0...This may be a test suite configuration error as the normal case works (and indeed I get a lot of profiled case failures of other cases). When run with an llvm-perf build of the HEAD, I get:
```
=====> T7837(normal) 1395 of 4068 [0, 0, 0]
cd ./indexed-types/should_compile && '/Users/jrp/Projects/haskell/ghc/inplace/bin/ghc-stage2' -fforce-recomp -dcore-lint -dcmm-lint -dno-debug-output -no-user-package-db -rtsopts -fno-ghci-history -c T7837.hs -O -ddump-rule-firings >T7837.comp.stderr 2>&1
=====> T7837(profasm) 1395 of 4068 [0, 0, 0]
cd ./indexed-types/should_compile && '/Users/jrp/Projects/haskell/ghc/inplace/bin/ghc-stage2' -fforce-recomp -dcore-lint -dcmm-lint -dno-debug-output -no-user-package-db -rtsopts -fno-ghci-history -c T7837.hs -O -prof -static -auto-all -O -ddump-rule-firings >T7837.comp.stderr 2>&1
Actual stderr output differs from expected:
--- ./indexed-types/should_compile/T7837.stderr 2014-08-03 11:36:53.000000000 +0100
+++ ./indexed-types/should_compile/T7837.comp.stderr 2014-08-04 23:16:34.000000000 +0100
@@ -1,3 +1,4 @@
Rule fired: Class op abs
Rule fired: Class op signum
Rule fired: normalize/Double
+Rule fired: Class op /
*** unexpected failure for T7837(profasm)
Unexpected results from:
TEST="T7837"
OVERALL SUMMARY for test run started at Mon Aug 4 23:16:32 2014 BST
0:00:02 spent to go through
4068 total tests, which gave rise to
19536 test cases, of which
19534 were skipped
0 had missing libraries
1 expected passes
0 expected failures
0 caused framework failures
0 unexpected passes
1 unexpected failures
Unexpected failures:
indexed-types/should_compile T7837 [stderr mismatch] (profasm)
```https://gitlab.haskell.org/ghc/ghc/-/issues/9534IEEE Standard 754 for Binary Floating-Point Arithmetic by Prof. W. Kahan, UCB2019-07-07T18:40:07Zjrp2014IEEE Standard 754 for Binary Floating-Point Arithmetic by Prof. W. Kahan, UCBThe attached is an implementation of the floating point accuracy test described in *The Baleful Influence of Benchmarks* section of http://www.eecs.berkeley.edu/\~wkahan/ieee754status/IEEE754.PDF
```
Results for Float:
r = 4098.0 produc...The attached is an implementation of the floating point accuracy test described in *The Baleful Influence of Benchmarks* section of http://www.eecs.berkeley.edu/\~wkahan/ieee754status/IEEE754.PDF
```
Results for Float:
r = 4098.0 produces 12.0 and 12.0 sig. bits
r = 4098.25 fails: root 0.99989897 isn't at least 1 <<<<
r = 4097.004 produces 12.0 and 11.999298 sig. bits
:
Worst accuracy is 11.999298 sig. bits
:
Results for Double:
r = 4098.0 produces Infinity and Infinity sig. bits
r = 4098.25 produces Infinity and 53.0 sig. bits
r = 4097.00390625 produces Infinity and 53.451178091541244 sig. bits
r = 1.6777218e7 produces Infinity and Infinity sig. bits
r = 1.677721825e7 produces Infinity and 75.0 sig. bits
r = 1.6777219e7 produces Infinity and 71.0 sig. bits
r = 9.4906267e7 produces 26.499999994288153 and 26.499999986733027 sig. bits
r = 9.490626725e7 fails: root 0.999999995635551 isn't at least 1 <<<
r = 2.684354505e8 produces 28.0 and 27.999999919383132 sig. bits
r = 2.684354515e8 produces 28.0 and 27.99999993013205 sig. bits
r = 2.68435458e8 produces 28.0 and 28.0 sig. bits
r = 2.6843545825e8 produces 28.0 and 28.00000000268723 sig. bits
r = 2.6843545700000006e8 produces 28.0 and 27.999999989251084 sig. bits
r = 4.294967298e9 produces 32.0 and 32.0 sig. bits
r = 4.29496729825e9 produces 32.0 and 32.00000000016795 sig. bits
Worst accuracy is 26.499999986733027 sig. bits
```
This seems to be comparable to a clang version, but seems to be fairly poor in comparison to some other machines, back in the day (1997).
**The attached could, possibly be turned into a testsuite test, by removing the QuickCheck tests that are included.**
Observations:
- There are a couple of failures (could be the implementation of sqrt or log).
- signum seems incorrect (signum Nan = -1.0)
- The prelude should have a copysign function
- min fails to produce the other argument if one argument is NaN
- The CFloat and CDouble variants seem to produce the same result as the native Float and Double versions
- The Haskell coding style could be improved to remove some boilerplate, make the code more idiomatic
- There may be a better way of entering the test values of r to ensure that they are accurate
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Task |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Test Suite |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"IEEE Standard 754 for Binary Floating-Point Arithmetic by Prof. W. Kahan, UCB","status":"New","operating_system":"","component":"Test Suite","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":["IEEE754"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Task","description":"The attached is an implementation of the floating point accuracy test described in ''The Baleful Influence of Benchmarks'' section of http://www.eecs.berkeley.edu/~wkahan/ieee754status/IEEE754.PDF\r\n\r\n\r\n{{{\r\nResults for Float:\r\nr = 4098.0 produces 12.0 and 12.0 sig. bits\r\nr = 4098.25 fails: root 0.99989897 isn't at least 1 <<<<\r\nr = 4097.004 produces 12.0 and 11.999298 sig. bits\r\n:\r\nWorst accuracy is 11.999298 sig. bits\r\n\r\n:\r\n\r\nResults for Double:\r\nr = 4098.0 produces Infinity and Infinity sig. bits\r\nr = 4098.25 produces Infinity and 53.0 sig. bits\r\nr = 4097.00390625 produces Infinity and 53.451178091541244 sig. bits\r\nr = 1.6777218e7 produces Infinity and Infinity sig. bits\r\nr = 1.677721825e7 produces Infinity and 75.0 sig. bits\r\nr = 1.6777219e7 produces Infinity and 71.0 sig. bits\r\nr = 9.4906267e7 produces 26.499999994288153 and 26.499999986733027 sig. bits\r\nr = 9.490626725e7 fails: root 0.999999995635551 isn't at least 1 <<<\r\nr = 2.684354505e8 produces 28.0 and 27.999999919383132 sig. bits\r\nr = 2.684354515e8 produces 28.0 and 27.99999993013205 sig. bits\r\nr = 2.68435458e8 produces 28.0 and 28.0 sig. bits\r\nr = 2.6843545825e8 produces 28.0 and 28.00000000268723 sig. bits\r\nr = 2.6843545700000006e8 produces 28.0 and 27.999999989251084 sig. bits\r\nr = 4.294967298e9 produces 32.0 and 32.0 sig. bits\r\nr = 4.29496729825e9 produces 32.0 and 32.00000000016795 sig. bits\r\nWorst accuracy is 26.499999986733027 sig. bits\r\n}}}\r\n\r\nThis seems to be comparable to a clang version, but seems to be fairly poor in comparison to some other machines, back in the day (1997).\r\n\r\n'''The attached could, possibly be turned into a testsuite test, by removing the QuickCheck tests that are included.'''\r\n\r\nObservations:\r\n\r\n* There are a couple of failures (could be the implementation of sqrt or log). \r\n* signum seems incorrect (signum Nan = -1.0)\r\n* The prelude should have a copysign function\r\n* min fails to produce the other argument if one argument is NaN\r\n* The CFloat and CDouble variants seem to produce the same result as the native Float and Double versions\r\n* The Haskell coding style could be improved to remove some boilerplate, make the code more idiomatic\r\n* There may be a better way of entering the test values of r to ensure that they are accurate\r\n\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/9765Strange behavior of GC under ghci2019-07-07T18:39:08ZremdezxStrange behavior of GC under ghciReleasing the result of `newForeignPtr nullFunPtr nullPtr` end in core dump, due to the fact that finalizer function is set to null pointer.
When I run something like this in GHCI:
```hs
> import System.Mem
> import Foreign.Ptr
> impo...Releasing the result of `newForeignPtr nullFunPtr nullPtr` end in core dump, due to the fact that finalizer function is set to null pointer.
When I run something like this in GHCI:
```hs
> import System.Mem
> import Foreign.Ptr
> import Foreign.ForeignPtr
> import System.IO.Unsafe
> import qualified Data.Map as Map
> a <- return $ Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package containers-0.5.5.1 ... linking ... done.
> print a
fromList [(1,0x0000000000000000)]
> performGC
> ^D
Leaving GHCi.
[1] 3782 segmentation fault (core dumped) ghci
```
it wont crash until exit from ghci which is correct. But if I do something similar but using `let` binding it will crash even if variable `a` didn't lose its scope
```hs
> import System.Mem
> import Foreign.Ptr
> import Foreign.ForeignPtr
> import System.IO.Unsafe
> import qualified Data.Map as Map
> let a = Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package containers-0.5.5.1 ... linking ... done.
> print a
fromList [(1,0x0000000000000000)]
[1] 3842 segmentation fault (core dumped) ghci
```
Why is there a difference between doing it with `do` notation and with `let` binding?
I also expected that if I rebind variable `a` it will lose it's scope and will be released but it is not (see below)
```hs
> import System.Mem
> import Foreign.Ptr
> import Foreign.ForeignPtr
> import System.IO.Unsafe
> import qualified Data.Map as Map
> a <- return $ Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)
Loading package array-0.5.0.0 ... linking ... done.
Loading package deepseq-1.3.0.2 ... linking ... done.
Loading package containers-0.5.5.1 ... linking ... done.
> print a
fromList [(1,0x0000000000000000)]
> a <- return () -- rebinding varable a, it is no longer used
> performGC
> -- no crash, varaible a not released
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.8.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | GHCi |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | hvr |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Strange behavior of GC under ghci","status":"New","operating_system":"","component":"GHCi","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["hvr"],"type":"Bug","description":"Releasing the result of `newForeignPtr nullFunPtr nullPtr` end in core dump, due to the fact that finalizer function is set to null pointer.\r\n\r\nWhen I run something like this in GHCI:\r\n{{{#!hs\r\n> import System.Mem\r\n> import Foreign.Ptr \r\n> import Foreign.ForeignPtr\r\n> import System.IO.Unsafe\r\n> import qualified Data.Map as Map\r\n> a <- return $ Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)\r\nLoading package array-0.5.0.0 ... linking ... done.\r\nLoading package deepseq-1.3.0.2 ... linking ... done.\r\nLoading package containers-0.5.5.1 ... linking ... done.\r\n> print a\r\nfromList [(1,0x0000000000000000)]\r\n> performGC\r\n> ^D\r\nLeaving GHCi.\r\n[1] 3782 segmentation fault (core dumped) ghci\r\n}}}\r\n\r\nit wont crash until exit from ghci which is correct. But if I do something similar but using `let` binding it will crash even if variable `a` didn't lose its scope\r\n{{{#!hs\r\n> import System.Mem\r\n> import Foreign.Ptr \r\n> import Foreign.ForeignPtr\r\n> import System.IO.Unsafe\r\n> import qualified Data.Map as Map\r\n> let a = Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)\r\nLoading package array-0.5.0.0 ... linking ... done.\r\nLoading package deepseq-1.3.0.2 ... linking ... done.\r\nLoading package containers-0.5.5.1 ... linking ... done.\r\n> print a\r\nfromList [(1,0x0000000000000000)]\r\n[1] 3842 segmentation fault (core dumped) ghci\r\n}}}\r\n\r\nWhy is there a difference between doing it with `do` notation and with `let` binding?\r\n\r\nI also expected that if I rebind variable `a` it will lose it's scope and will be released but it is not (see below)\r\n{{{#!hs\r\n> import System.Mem\r\n> import Foreign.Ptr \r\n> import Foreign.ForeignPtr\r\n> import System.IO.Unsafe\r\n> import qualified Data.Map as Map\r\n> a <- return $ Map.singleton 1 (unsafePerformIO $ newForeignPtr nullFunPtr nullPtr)\r\nLoading package array-0.5.0.0 ... linking ... done.\r\nLoading package deepseq-1.3.0.2 ... linking ... done.\r\nLoading package containers-0.5.5.1 ... linking ... done.\r\n> print a\r\nfromList [(1,0x0000000000000000)]\r\n> a <- return () -- rebinding varable a, it is no longer used\r\n> performGC\r\n> -- no crash, varaible a not released\r\n}}}\r\n","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/9936Data.Fixed truncates 5.17 to 5.162019-07-07T18:38:21ZsingpolymaData.Fixed truncates 5.17 to 5.16`(realToFrac (5.17 :: Double) :: Centi) == 5.16`
is true -- it should be false.
The offender seems to be the assumption in `fromRational`:
`fromRational r = withResolution (\res -> MkFixed (floor (r * (toRational res))))`
Uses `floor`...`(realToFrac (5.17 :: Double) :: Centi) == 5.16`
is true -- it should be false.
The offender seems to be the assumption in `fromRational`:
`fromRational r = withResolution (\res -> MkFixed (floor (r * (toRational res))))`
Uses `floor` assuming that the underlying floating point value is stored purely and not as 0.999999 or similar -- switching it to `round` fixes this issue.
<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 | ekmett, hvr |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Data.Fixed truncates 5.17 to 5.16","status":"New","operating_system":"","component":"libraries/base","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["ekmett","hvr"],"type":"Bug","description":"`(realToFrac (5.17 :: Double) :: Centi) == 5.16`\r\nis true -- it should be false.\r\n\r\nThe offender seems to be the assumption in `fromRational`:\r\n\r\n`fromRational r = withResolution (\\res -> MkFixed (floor (r * (toRational res))))`\r\n\r\nUses `floor` assuming that the underlying floating point value is stored purely and not as 0.999999 or similar -- switching it to `round` fixes this issue.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/10046Linker script patch in rts/Linker.c doesn't work for (non-C or non-en..) locales2019-07-07T18:37:48ZHoward B. GoldenLinker script patch in rts/Linker.c doesn't work for (non-C or non-en..) localesPlease see [ticket:2615\#comment:95729](https://gitlab.haskell.org//ghc/ghc/issues/2615#note_95729) and replies.
A bug is illustrated by this Haskell program:
```
import ObjLink
import Foreign
import Foreign.C.Types
import Foreign.C.St...Please see [ticket:2615\#comment:95729](https://gitlab.haskell.org//ghc/ghc/issues/2615#note_95729) and replies.
A bug is illustrated by this Haskell program:
```
import ObjLink
import Foreign
import Foreign.C.Types
import Foreign.C.String
foreign import ccall "setlocale" c_setlocale :: CInt -> CString -> IO CString
main = do
withCString "zh_CN.UTF-8" $ \lc -> c_setlocale 5 lc
r <- loadDLL "/usr/lib/libc.so"
putStrLn (show r)
```
which outputs:
```
Just "/usr/lib/libc.so: \26080\25928\30340 ELF \22836"
```
The "\\26080\\25928\\30340 ELF \\22836" part is "无效的ELF头" in Chinese.
This error only occurs on systems where linker scripts are used. The linker script patch (as it has evolved) assumes that the error messages it will receive are in English. This would be true if the locale (LC_MESSAGES) is C or en (or one of the en variants). However, in other locales, the message will be in a different language. Unfortunately, the semantics of POSIX dlerror() specify that the error is returned as a pointer to a human-readable text string, rather than an error code. The string returned depends on the locale.
The code could be made more robust by momentarily changing the locale (LC_MESSAGES) to C before calling dlerror() and reverting it to its previous value immediately after. This has been tested on a zh_CN.utf-8 (see [ticket:2615\#comment:95752](https://gitlab.haskell.org//ghc/ghc/issues/2615#note_95752)) and works. The only concern I have is in the case of multithreaded code that _might_ be affected if it is running while the locale is changed. I don't know enough to know if this is a real issue or not, nor do I know how to deal with it if necessary.
Also see #9237 for another corner case in the linker script code that should be dealt with at the same time.8.0.1Simon MarlowSimon Marlowhttps://gitlab.haskell.org/ghc/ghc/-/issues/10111hp2ps silently discards samples2019-07-07T18:37:27ZEdward Z. Yanghp2ps silently discards samplesConsider the following hp file:
```
JOB "whatever"
DATE "Sat Feb 21 12:56 2015"
SAMPLE_UNIT "seconds"
VALUE_UNIT "bytes"
BEGIN_SAMPLE 0.00
MAIN 1000
END_SAMPLE 0.00
BEGIN_SAMPLE 0.00
MAIN 100
END_SAMPLE 0.00
BEGIN_SAMPLE 0.01
MAIN 500
E...Consider the following hp file:
```
JOB "whatever"
DATE "Sat Feb 21 12:56 2015"
SAMPLE_UNIT "seconds"
VALUE_UNIT "bytes"
BEGIN_SAMPLE 0.00
MAIN 1000
END_SAMPLE 0.00
BEGIN_SAMPLE 0.00
MAIN 100
END_SAMPLE 0.00
BEGIN_SAMPLE 0.01
MAIN 500
END_SAMPLE 0.01
```
hp2ps will generate a graph showing heap usage going from 100 bytes to 500 bytes... not 1000-100-500 as expected. This is because hp2ps only uses the last sample with the same timestamp.
These hp files show in practice because GHC doesn't output BEGIN_SAMPLE entries with enough precision, see also https://phabricator.haskell.org/D679 to increase the precision.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.11 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Profiling |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"hp2ps silently discards samples","status":"New","operating_system":"","component":"Profiling","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.11","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Consider the following hp file:\r\n\r\n{{{\r\nJOB \"whatever\"\r\nDATE \"Sat Feb 21 12:56 2015\"\r\nSAMPLE_UNIT \"seconds\"\r\nVALUE_UNIT \"bytes\"\r\nBEGIN_SAMPLE 0.00\r\nMAIN\t1000\r\nEND_SAMPLE 0.00\r\nBEGIN_SAMPLE 0.00\r\nMAIN\t100\r\nEND_SAMPLE 0.00\r\nBEGIN_SAMPLE 0.01\r\nMAIN\t500\r\nEND_SAMPLE 0.01\r\n}}}\r\n\r\nhp2ps will generate a graph showing heap usage going from 100 bytes to 500 bytes... not 1000-100-500 as expected. This is because hp2ps only uses the last sample with the same timestamp.\r\n\r\nThese hp files show in practice because GHC doesn't output BEGIN_SAMPLE entries with enough precision, see also https://phabricator.haskell.org/D679 to increase the precision.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/11201ghc --make on Haskell and non-Haskell inputs can silently clobber input2019-07-07T18:31:29ZEdward Z. Yangghc --make on Haskell and non-Haskell inputs can silently clobber inputCreate any valid files A.hs and A.c, then run `ghc --make A.hs A.c`. You'll get one `A.o` file for `A.hs`; the `A.o` from `A.c` is lost to the sands of time.
I thought this situation would be pretty unlikely but geekosaur mentioned to m...Create any valid files A.hs and A.c, then run `ghc --make A.hs A.c`. You'll get one `A.o` file for `A.hs`; the `A.o` from `A.c` is lost to the sands of time.
I thought this situation would be pretty unlikely but geekosaur mentioned to me that he had seen someone run into this problem before.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.11 |
| 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":"ghc --make on Haskell and non-Haskell inputs can silently clobber input","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.11","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Create any valid files A.hs and A.c, then run `ghc --make A.hs A.c`. You'll get one `A.o` file for `A.hs`; the `A.o` from `A.c` is lost to the sands of time.\r\n\r\nI thought this situation would be pretty unlikely but geekosaur mentioned to me that he had seen someone run into this problem before.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/11215Line endings in quasiquotations are not normalised2019-07-07T18:31:26ZrefoldLine endings in quasiquotations are not normalisedConsider the following [simple quasiquoter](http://hackage.haskell.org/package/raw-strings-qq):
```hs
foo = QuasiQuoter {
quoteExp = return . LitE . StringL
[...]
```
When used like this:
```hs
bar :: String
bar = [foo|FO...Consider the following [simple quasiquoter](http://hackage.haskell.org/package/raw-strings-qq):
```hs
foo = QuasiQuoter {
quoteExp = return . LitE . StringL
[...]
```
When used like this:
```hs
bar :: String
bar = [foo|FOO
BAR
BAZ|]
```
the string `bar` will contain either LF or CRLF line endings depending on which convention is used in the file.
This is consistent with documentation, if a bit surprising. However, the problem is that version control systems (e.g. Git) usually store text files using Unix line endings, but allow checking them out in a platform-specific format. So this behaviour gives rise to subtle semantics changes in the compiled program that depend on the user's VCS settings. Therefore IMO it makes sense to always normalise CRLF to LF in quasiquotations.
Originally reported [here](https://github.com/23Skidoo/raw-strings-qq/issues/1), a test case can be found [here](https://github.com/23Skidoo/raw-strings-qq/blob/master/test/Test.hs).
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ----------------- |
| Version | 7.10.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler (Parser) |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Line endings in quasiquotations are not normalised","status":"New","operating_system":"","component":"Compiler (Parser)","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.10.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Consider the following [http://hackage.haskell.org/package/raw-strings-qq simple quasiquoter]:\r\n\r\n{{{#!hs\r\nfoo = QuasiQuoter {\r\n quoteExp = return . LitE . StringL\r\n [...]\r\n}}}\r\n\r\nWhen used like this:\r\n\r\n{{{#!hs\r\nbar :: String\r\nbar = [foo|FOO\r\nBAR\r\nBAZ|]\r\n}}}\r\n\r\nthe string `bar` will contain either LF or CRLF line endings depending on which convention is used in the file.\r\n\r\nThis is consistent with documentation, if a bit surprising. However, the problem is that version control systems (e.g. Git) usually store text files using Unix line endings, but allow checking them out in a platform-specific format. So this behaviour gives rise to subtle semantics changes in the compiled program that depend on the user's VCS settings. Therefore IMO it makes sense to always normalise CRLF to LF in quasiquotations.\r\n\r\nOriginally reported [https://github.com/23Skidoo/raw-strings-qq/issues/1 here], a test case can be found [https://github.com/23Skidoo/raw-strings-qq/blob/master/test/Test.hs here].","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/11312GHC inlining primitive string literals can affect program output2019-07-07T18:30:58ZRyan ScottGHC inlining primitive string literals can affect program outputFirst noted in #11292, this program, when compiled with `-O1` or higher:
```hs
{-# LANGUAGE MagicHash #-}
module Main (main) where
import GHC.Exts (Addr#, isTrue#)
import GHC.Prim (eqAddr#)
data A = A { runA :: Addr# }
a :: A
a = A "...First noted in #11292, this program, when compiled with `-O1` or higher:
```hs
{-# LANGUAGE MagicHash #-}
module Main (main) where
import GHC.Exts (Addr#, isTrue#)
import GHC.Prim (eqAddr#)
data A = A { runA :: Addr# }
a :: A
a = A "a"#
main :: IO ()
main = print (isTrue# (eqAddr# (runA a) (runA a)))
```
will result in the following after inlining:
```
Main.main2 =
case GHC.Prim.tagToEnum#
@ GHC.Types.Bool (GHC.Prim.eqAddr# "a"# "a"#)
of _ [Occ=Dead] {
GHC.Types.False -> GHC.Show.shows26;
GHC.Types.True -> GHC.Show.shows24
}
```
As a result, there are two of the same string constant with different addresses, which causes `eqAddr#` to return `False`. If compiled without optimizations, `"a"#` is not inlined, and as a result, `eqAddr#` returns `True`.
Two questions:
1. Is this okay semantics-wise? Or is this a necessary risk when working with primitive string literals, and should programmers judiciously use `{-# NOINLINE #-}` with them?
1. Is this okay from a code duplication standpoint? As Reid Barton noted in #11292, `"a"#` is duplicated due to inlining. In this example, not much is duplicated, but if it were a longer string constant, that could result in a noticeable increase in the object file size.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 7.10.3 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | #11292 |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"GHC inlining primitive string literals can affect program output","status":"New","operating_system":"","component":"Compiler","related":[11292],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.10.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"First noted in #11292, this program, when compiled with `-O1` or higher:\r\n\r\n{{{#!hs\r\n{-# LANGUAGE MagicHash #-}\r\nmodule Main (main) where\r\n\r\nimport GHC.Exts (Addr#, isTrue#)\r\nimport GHC.Prim (eqAddr#)\r\n\r\ndata A = A { runA :: Addr# }\r\n\r\na :: A\r\na = A \"a\"#\r\n\r\nmain :: IO ()\r\nmain = print (isTrue# (eqAddr# (runA a) (runA a)))\r\n}}}\r\n\r\nwill result in the following after inlining:\r\n\r\n{{{\r\nMain.main2 =\r\n case GHC.Prim.tagToEnum#\r\n @ GHC.Types.Bool (GHC.Prim.eqAddr# \"a\"# \"a\"#)\r\n of _ [Occ=Dead] {\r\n GHC.Types.False -> GHC.Show.shows26;\r\n GHC.Types.True -> GHC.Show.shows24\r\n }\r\n}}}\r\n\r\nAs a result, there are two of the same string constant with different addresses, which causes `eqAddr#` to return `False`. If compiled without optimizations, `\"a\"#` is not inlined, and as a result, `eqAddr#` returns `True`.\r\n\r\nTwo questions:\r\n\r\n1. Is this okay semantics-wise? Or is this a necessary risk when working with primitive string literals, and should programmers judiciously use `{-# NOINLINE #-}` with them?\r\n2. Is this okay from a code duplication standpoint? As Reid Barton noted in #11292, `\"a\"#` is duplicated due to inlining. In this example, not much is duplicated, but if it were a longer string constant, that could result in a noticeable increase in the object file size.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/11553`round (± ∞ :: Double)` not infinite2019-07-07T18:29:51ZHerbert Valerio Riedelhvr@gnu.org`round (± ∞ :: Double)` not infiniteRounding 1/0 or -1/0 results in an arbitrary chosen `Integer` value, e.g.
```
λ:2> (round (1/0 :: Double) :: Integer) == 2^1024
True
λ:3> (round (-1/0 :: Double) :: Integer) == -(2^1024)
True
λ:4> (round (0/0 :: Double) :: Integer) ...Rounding 1/0 or -1/0 results in an arbitrary chosen `Integer` value, e.g.
```
λ:2> (round (1/0 :: Double) :: Integer) == 2^1024
True
λ:3> (round (-1/0 :: Double) :: Integer) == -(2^1024)
True
λ:4> (round (0/0 :: Double) :: Integer) == -(2^1024 + 2^1023)
True
```
I'm not sure if this is more desirable than returning a bottom value (e.g. by throwing some `ArithException`)https://gitlab.haskell.org/ghc/ghc/-/issues/11628Unexpected results with Read/Show2019-07-07T18:29:25ZEric CrockettUnexpected results with Read/ShowIn the following simplified example, `Foo` and `U` correspond to GADTs that GHC will not derive `Read`/`Show` for. I attempted to work around that by using newtypes for each GADT constructor, and letting GHC derive the `Show`/`Read` inst...In the following simplified example, `Foo` and `U` correspond to GADTs that GHC will not derive `Read`/`Show` for. I attempted to work around that by using newtypes for each GADT constructor, and letting GHC derive the `Show`/`Read` instances for those instead. However, I get a runtime error (`Prelude.read: no parse`) on the second print statement in `main`:
```
{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, ScopedTypeVariables #-}
import Text.Read (Read(readPrec))
newtype Bar r = Bar r deriving (Show, Read)
newtype Foo r = Foo (Bar r)
-- use the GHC-derived Show/Read for Bar
instance (Show r) => Show (Foo r) where
show (Foo x) = show x
instance (Read r) => Read (Foo r) where
readPrec = Foo <$> readPrec
data U t rep r where
U1 :: t r -> U t Int r
U2 :: t r -> U t Char r
-- use the Read/Show instances for U1Wrap and U2Wrap
newtype U1Wrap t r = U1Wrap {unU1Wrap :: t r} deriving (Show, Read)
newtype U2Wrap t r = U2Wrap (t r) deriving (Show, Read)
instance (Read (t r)) => Read (U t Int r) where
readPrec = (U1 . unU1Wrap) <$> readPrec
instance (Read (U2Wrap t r)) => Read (U t Char r) where
readPrec = do
x <- readPrec
return $ case x of
(U2Wrap y) -> U2 y
instance (Show (t r)) => Show (U t Int r) where
show (U1 x) = show $ U1Wrap x
instance (Show (t r)) => Show (U t Char r) where
show (U2 x) = show (U2Wrap x :: U2Wrap t r)
main :: IO ()
main = do
let x = U1 $ Foo $ Bar 3
y = U2 $ Foo $ Bar 3
print $ show (read (show x) `asTypeOf` x)
print $ show (read (show y) `asTypeOf` y)
```
Someone mentioned that I should define `showsPrec` rather than `show`, but these are listed as alternatives in [the docs](https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.8.2.0/Text-Show.html).
It's not clear to me if GHCs derived instances are invalid, or if I'm doing something illegal. In the latter case, the docs need some improvement.
(Verified this behavior in 7.10.2 and HEAD.)
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------------ |
| Version | 7.10.3 |
| Type | Bug |
| TypeOfFailure | IncorrectResultAtRuntime |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Unexpected results with Read/Show","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.10.3","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"In the following simplified example, `Foo` and `U` correspond to GADTs that GHC will not derive `Read`/`Show` for. I attempted to work around that by using newtypes for each GADT constructor, and letting GHC derive the `Show`/`Read` instances for those instead. However, I get a runtime error (`Prelude.read: no parse`) on the second print statement in `main`:\r\n\r\n{{{\r\n{-# LANGUAGE FlexibleContexts, FlexibleInstances, GADTs, ScopedTypeVariables #-}\r\n\r\nimport Text.Read (Read(readPrec))\r\n\r\nnewtype Bar r = Bar r deriving (Show, Read)\r\nnewtype Foo r = Foo (Bar r)\r\n-- use the GHC-derived Show/Read for Bar\r\ninstance (Show r) => Show (Foo r) where\r\n show (Foo x) = show x\r\ninstance (Read r) => Read (Foo r) where\r\n readPrec = Foo <$> readPrec\r\n\r\ndata U t rep r where\r\n U1 :: t r -> U t Int r\r\n U2 :: t r -> U t Char r\r\n-- use the Read/Show instances for U1Wrap and U2Wrap\r\nnewtype U1Wrap t r = U1Wrap {unU1Wrap :: t r} deriving (Show, Read)\r\nnewtype U2Wrap t r = U2Wrap (t r) deriving (Show, Read)\r\ninstance (Read (t r)) => Read (U t Int r) where\r\n readPrec = (U1 . unU1Wrap) <$> readPrec\r\ninstance (Read (U2Wrap t r)) => Read (U t Char r) where\r\n readPrec = do\r\n x <- readPrec\r\n return $ case x of\r\n (U2Wrap y) -> U2 y\r\ninstance (Show (t r)) => Show (U t Int r) where\r\n show (U1 x) = show $ U1Wrap x\r\ninstance (Show (t r)) => Show (U t Char r) where\r\n show (U2 x) = show (U2Wrap x :: U2Wrap t r)\r\n\r\nmain :: IO ()\r\nmain = do\r\n let x = U1 $ Foo $ Bar 3\r\n y = U2 $ Foo $ Bar 3\r\n print $ show (read (show x) `asTypeOf` x)\r\n print $ show (read (show y) `asTypeOf` y)\r\n}}}\r\n\r\nSomeone mentioned that I should define `showsPrec` rather than `show`, but these are listed as alternatives in [https://downloads.haskell.org/~ghc/latest/docs/html/libraries/base-4.8.2.0/Text-Show.html the docs].\r\n\r\nIt's not clear to me if GHCs derived instances are invalid, or if I'm doing something illegal. In the latter case, the docs need some improvement.\r\n\r\n(Verified this behavior in 7.10.2 and HEAD.)","type_of_failure":"IncorrectResultAtRuntime","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/12556`stimes` adds extra power to Semigroup2019-07-07T18:26:07ZIcelandjack`stimes` adds extra power to Semigroup```
ghci> stimes 0 (undefined :: [_])
[]
ghci> stimes 0 undefined
()
```
makes it seem like `stimes 0` has some knowledge about `mempty` from `Monoid` but it has the following type
```hs
stimes 0 :: Semigroup a => a -> a
```
Desired ...```
ghci> stimes 0 (undefined :: [_])
[]
ghci> stimes 0 undefined
()
```
makes it seem like `stimes 0` has some knowledge about `mempty` from `Monoid` but it has the following type
```hs
stimes 0 :: Semigroup a => a -> a
```
Desired behaviour? Given that type (assuming it only has the power of `<>`) I would have assumed this behaviour
```
ghci> data L a = N | C a (L a) deriving Show
ghci> instance Semigroup (L a) where (<>) = undefined
ghci|
ghci> stimes 0 (undefined :: L _)
*** Exception: stimes: positive multiplier expected
```https://gitlab.haskell.org/ghc/ghc/-/issues/12678-threaded is listed as a dynamic flag but is silently ignored in OPTIONS_GHC2019-07-07T18:25:36Zenolan-threaded is listed as a dynamic flag but is silently ignored in OPTIONS_GHCHi GHC folks.
In section 6.1.2.2 of the user's guide it says "Only dynamic flags can be used in an OPTIONS_GHC pragma" and in section 6.6 it says `-threaded` is a dynamic flag. However, the following program compiles successfully but do...Hi GHC folks.
In section 6.1.2.2 of the user's guide it says "Only dynamic flags can be used in an OPTIONS_GHC pragma" and in section 6.6 it says `-threaded` is a dynamic flag. However, the following program compiles successfully but doesn't get linked with the threaded RTS unless I add the option on the command line:
```hs
{-# OPTIONS_GHC -threaded #-}
main = return ()
```
Running `./foo +RTS --info` reports `("RTS way", "rts_v")` when it should say `rts_thr`.
Either `-threaded` should be settable in `OPTIONS_GHC` pragmas, or setting it should be an error that aborts compilation. The documentation should accurately state the rules regardless.
This happens on 8.0.1, 7.10.3 and the `ghc-8.0` branch. I didn't check master.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------ |
| Version | 8.0.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"-threaded is listed as a dynamic flag but is silently ignored in OPTIONS_GHC","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"Bug","description":"Hi GHC folks.\r\n\r\nIn section 6.1.2.2 of the user's guide it says \"Only dynamic flags can be used in an OPTIONS_GHC pragma\" and in section 6.6 it says `-threaded` is a dynamic flag. However, the following program compiles successfully but doesn't get linked with the threaded RTS unless I add the option on the command line:\r\n\r\n{{{#!hs\r\n{-# OPTIONS_GHC -threaded #-}\r\n\r\nmain = return ()\r\n}}}\r\n\r\nRunning `./foo +RTS --info` reports `(\"RTS way\", \"rts_v\")` when it should say `rts_thr`.\r\n\r\nEither `-threaded` should be settable in `OPTIONS_GHC` pragmas, or setting it should be an error that aborts compilation. The documentation should accurately state the rules regardless.\r\n\r\nThis happens on 8.0.1, 7.10.3 and the `ghc-8.0` branch. I didn't check master.","type_of_failure":"OtherFailure","blocking":[]} -->https://gitlab.haskell.org/ghc/ghc/-/issues/12750hGetContents leads to late/silent failures2019-07-07T18:25:18Zmassimo.zanibonihGetContents leads to late/silent failuresI have the same problem described in the closed ticket #9236
This is a test-case https://github.com/massimo-zaniboni/ghc_lazy_file_content_error
I tried with ghc 7.10.3 and 8.0.1
<details><summary>Trac metadata</summary>
| Trac field...I have the same problem described in the closed ticket #9236
This is a test-case https://github.com/massimo-zaniboni/ghc_lazy_file_content_error
I tried with ghc 7.10.3 and 8.0.1
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------------ |
| Version | 8.0.1 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Core Libraries |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | ekmett, massimo.zaniboni |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"hGetContents leads to late/silent failures","status":"New","operating_system":"","component":"Core Libraries","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"8.0.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["ekmett","massimo.zaniboni"],"type":"Bug","description":"I have the same problem described in the closed ticket #9236\r\n\r\nThis is a test-case https://github.com/massimo-zaniboni/ghc_lazy_file_content_error\r\n\r\nI tried with ghc 7.10.3 and 8.0.1\r\n\r\n","type_of_failure":"OtherFailure","blocking":[]} -->