Segfault in a CoreLinted program (and a GHC-generated Core question)

I have a very simple Core plugin that generates some functions. After my Core-to-Core pass is done, I'm running the linter to make sure the Core generated by my plugin is well-formed and well-typed. However, even though lint checker passes, the code generated by my plugin is failing with a segfault. I created a git repo for demonstration: https://github.com/osa1/plugins This is where the CoreLint is happening: https://github.com/osa1/plugins/blob/master/src/Plugins.hs#L38 I'm using GHC HEAD(it doesn't build with 7.10). Here's how to run: Make sure GHC HEAD is in the $PATH, then $ cabal install --with-ghc=ghc-stage2 $ cd test Adding bunch of -ddump parameters here for debugging purposes: $ ghc-stage2 -fplugin=Plugins --make Main.hs -fforce-recomp -ddump-simpl -ddump-ds -ddump-to-file -ddump-stg Now if you run the generated program, it should first print some numbers and then segfault. --- I heard from Simon in various talks(e.g. Haskell exchange 2015) that if lint passes, then there should be no segfaults, so I thought this should be a bug. I'm actually having some other problems with CoreLint too, for example, even though Core lint passes, if I run Core simplifier pass after my plugin runs, GHC is failing with various different panics. Some of those panics are happening inside STG generation, not in simplifier(but it works fine if I disable the simplifier!) It seems like CoreLint is not strict enough, it's not checking some invariants that GHC simplifier and STG code generator are assuming. So my questions are: Am I right in assuming that CoreLint accepted programs should not segfault? What about internal invariants? Should CoreLint check for those? Is there any pass that checks for invariants and prints helpful messages in case of a invariant invalidation? As an attempt at debugging the code generated by my plugin, I wrote the function that is supposed to be generated by my Core pass in Haskell and compiled with GHC. Generated Core is mostly the same, except at one point it has an extra lambda directly applied to a void#, something like ((\_ -> ...) void#). Where can I learn more about why GHC is doing that? Thanks.

Ömer Sinan Ağacan
I have a very simple Core plugin that generates some functions. After my Core-to-Core pass is done, I'm running the linter to make sure the Core generated by my plugin is well-formed and well-typed. However, even though lint checker passes, the code generated by my plugin is failing with a segfault.
...
So my questions are: Am I right in assuming that CoreLint accepted programs should not segfault? What about internal invariants? Should CoreLint check for those? Is there any pass that checks for invariants and prints helpful messages in case of a invariant invalidation?
My understanding is that CoreLint should (in principle) check all internal invariants necessary to ensure the soundness of the Core. If a Core program passes CoreLint it ought not to segfault. It sounds like you found a bug in CoreLint.
As an attempt at debugging the code generated by my plugin, I wrote the function that is supposed to be generated by my Core pass in Haskell and compiled with GHC. Generated Core is mostly the same, except at one point it has an extra lambda directly applied to a void#, something like ((\_ -> ...) void#). Where can I learn more about why GHC is doing that?
Hmm, interesting. I'm afraid I'm not sure what semantics void# has in Core but it sure does sound fishy. Sadly grepping the source tree for clues doesn't turn much up. Simon, perhaps you could comment here? Cheers, - Ben

| So my questions are: Am I right in assuming that CoreLint accepted programs | should not segfault? Yes. Modulo unsafeCoerce, and FFI calls. | What about internal invariants? Should CoreLint check | for those? Is there any pass that checks for invariants and prints helpful | messages in case of a invariant invalidation? Yes; they are documented in CoreSyn, which the data type, and Lint checks them. | As an attempt at debugging the code generated by my plugin, I wrote the | function that is supposed to be generated by my Core pass in Haskell and | compiled with GHC. Generated Core is mostly the same, except at one point it | has an extra lambda directly applied to a void#, something like ((\_ -> ...) | void#). Where can I learn more about why GHC is doing that? Show me the code! Instead of generating x :: Int# = <some expression that might fail> GHC sometimes generates x :: Void# -> Int# = \_ - <some expression that might fail> and then calls (x void#), to make any div-zero failures happen at the right place. I'm not sure if that is what you are seeing, but we can work it out when you give more detail. Simon

OK, thanks to people at IRC channel(especially @rwbarton) I realized
that my lint calls were not actually running, simply because I wasn't
using -dcore-lint.. I didn't know such a flag exists, and even with
the absence of the flag I'd expect a core lint would work, because I'm
explicitly calling the lint function without checking any flags!
CoreLint is now giving me really awesome diagnostics! Sorry for the noise..
(I'll try to document linter functions or CoreLint module to let the
user know he/she needs this flag!)
2015-10-26 13:43 GMT-04:00 Simon Peyton Jones
| So my questions are: Am I right in assuming that CoreLint accepted programs | should not segfault?
Yes. Modulo unsafeCoerce, and FFI calls.
| What about internal invariants? Should CoreLint check | for those? Is there any pass that checks for invariants and prints helpful | messages in case of a invariant invalidation?
Yes; they are documented in CoreSyn, which the data type, and Lint checks them.
| As an attempt at debugging the code generated by my plugin, I wrote the | function that is supposed to be generated by my Core pass in Haskell and | compiled with GHC. Generated Core is mostly the same, except at one point it | has an extra lambda directly applied to a void#, something like ((\_ -> ...) | void#). Where can I learn more about why GHC is doing that?
Show me the code!
Instead of generating
x :: Int# = <some expression that might fail>
GHC sometimes generates
x :: Void# -> Int# = \_ - <some expression that might fail>
and then calls (x void#), to make any div-zero failures happen at the right place.
I'm not sure if that is what you are seeing, but we can work it out when you give more detail.
Simon

Phew. This was an alarming email! If a core-linted program segfaults, there's either a bug in CoreLint or a bug in the theory behind GHC. If it's the latter, someone will have an interesting paper to write... :)
Richard
On Oct 26, 2015, at 7:57 PM, Ömer Sinan Ağacan
OK, thanks to people at IRC channel(especially @rwbarton) I realized that my lint calls were not actually running, simply because I wasn't using -dcore-lint.. I didn't know such a flag exists, and even with the absence of the flag I'd expect a core lint would work, because I'm explicitly calling the lint function without checking any flags!
CoreLint is now giving me really awesome diagnostics! Sorry for the noise..
(I'll try to document linter functions or CoreLint module to let the user know he/she needs this flag!)
2015-10-26 13:43 GMT-04:00 Simon Peyton Jones
: | So my questions are: Am I right in assuming that CoreLint accepted programs | should not segfault?
Yes. Modulo unsafeCoerce, and FFI calls.
| What about internal invariants? Should CoreLint check | for those? Is there any pass that checks for invariants and prints helpful | messages in case of a invariant invalidation?
Yes; they are documented in CoreSyn, which the data type, and Lint checks them.
| As an attempt at debugging the code generated by my plugin, I wrote the | function that is supposed to be generated by my Core pass in Haskell and | compiled with GHC. Generated Core is mostly the same, except at one point it | has an extra lambda directly applied to a void#, something like ((\_ -> ...) | void#). Where can I learn more about why GHC is doing that?
Show me the code!
Instead of generating
x :: Int# = <some expression that might fail>
GHC sometimes generates
x :: Void# -> Int# = \_ - <some expression that might fail>
and then calls (x void#), to make any div-zero failures happen at the right place.
I'm not sure if that is what you are seeing, but we can work it out when you give more detail.
Simon
ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Am Dienstag, den 27.10.2015, 09:44 -0400 schrieb Richard Eisenberg:
Phew. This was an alarming email! If a core-linted program segfaults, there's either a bug in CoreLint or a bug in the theory behind GHC. If it's the latter, someone will have an interesting paper to write... :)
... or in the translation to STG, or in a STG to STG pass, or in the translation to C--, or in a C-- to C-- pass, or in the code generator, or in the linker, or in... Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org

Didn't you know? Once the core-to-core passes are complete, a binary appears on disk by sheer magic. And magic is never wrong.
Richard
On Oct 27, 2015, at 10:28 AM, Joachim Breitner
Am Dienstag, den 27.10.2015, 09:44 -0400 schrieb Richard Eisenberg:
Phew. This was an alarming email! If a core-linted program segfaults, there's either a bug in CoreLint or a bug in the theory behind GHC. If it's the latter, someone will have an interesting paper to write... :)
... or in the translation to STG, or in a STG to STG pass, or in the translation to C--, or in a C-- to C-- pass, or in the code generator, or in the linker, or in...
Greetings, Joachim
-- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org
_______________________________________________ ghc-devs mailing list ghc-devs@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

Am Dienstag, den 27.10.2015, 10:41 -0400 schrieb Richard Eisenberg:
Didn't you know? Once the core-to-core passes are complete, a binary appears on disk by sheer magic. And magic is never wrong.
Ah, no, I didn’t. No wonder my feeble attempts to make the code generation for switches more efficient didn’t yield the desired performance boosts. Greetings, Joachim -- Joachim “nomeata” Breitner mail@joachim-breitner.de • http://www.joachim-breitner.de/ Jabber: nomeata@joachim-breitner.de • GPG-Key: 0xF0FBF51F Debian Developer: nomeata@debian.org
participants (5)
-
Ben Gamari
-
Joachim Breitner
-
Richard Eisenberg
-
Simon Peyton Jones
-
Ömer Sinan Ağacan