[GHC] #14647: Invalid C in the via-C backend due to EFF_

GHC ghc-devs at haskell.org
Mon Jan 8 01:55:42 UTC 2018


#14647: Invalid C in the via-C backend due to EFF_
-------------------------------------+-------------------------------------
           Reporter:                 |             Owner:  (none)
  ElvishJerricco                     |
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.3
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  Other
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:  #8965 #11395
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 {{{
 // Stg.h

 #define EFF_(f)   void f() /* See Note [External function prototypes] */
 }}}

 Whenever Cmm uses a foreign C symbol, the generated C will declare the
 symbol with `EFF_`. Later, it will cast it to the appropriate type before
 calling it, often casting it to `void *` beforehand. `EFF_` is used in
 case the symbol is needed multiple times at incompatible types. This is
 invalid and discouraged in standard C for a number of reasons.

 - Even with incomplete args lists, it is invalid to declare a function
 with an inaccurate return type.
 - Incomplete args lists is considered "an obsolescent feature" of C.
 - It is invalid to call a function declared with an incomplete args list
 at multiple incompatible types.
 - It is invalid to cast a function to `void *`, as function pointers can
 technically have different width than regular pointers. This one obviously
 doesn't matter very much.
 - Using incomplete args lists to declare a function implemented with
 varargs is invalid, though this isn't really solvable for `foreign import
 ccall` without requiring the user to annotate such imports as varargs
 functions.

 On all the platforms GHC currently supports, this happens to work out
 fine. The C ABI on most platforms makes all of this compatible. But I've
 been working on making GHC target WebAssembly with via-C, and WebAssembly
 does not currently support this. Although it is
 [https://bugs.llvm.org/show_bug.cgi?id=35385 an LLVM bug] that incomplete
 args lists are unsupported on WebAssembly, it's fair-game that the
 inaccurate return type and liberal casting is broken.

 The fix is to declare externs with the proper types. We shouldn't use top
 level extern declarations in case the same symbol needs to be declared
 with multiple incompatible types (though frankly, I can't think of a good
 reason for this to occur, aside from varargs symbols, which is already
 invalid). We can use local externs to avoid the type incompatibilities.

 {{{
 void foo() {
   extern int bar(int, int);
   ...
 }
 }}}

 The difficulty here is that Cmm doesn't carry the information necessary to
 make such declarations.

 {{{
 module Test where

 foreign import ccall unsafe "testCSymbol"
   testHaskellSymbol :: Int -> Int -> Int -> Int
 }}}

 {{{
 ghc -c Test.hs -o Test.o -ddump-cmm-raw
 }}}

 {{{
            ...
            _s17E::I64 = I64[_s17D::P64 + 7];
            _c188::I64 = testCSymbol;
            _c189::I64 = _s17A::I64;
            _c18a::I64 = _s17C::I64;
            _c18b::I64 = _s17E::I64;
            (_s17I::I64) = call "ccall" arg hints:  [‘signed’, ‘signed’,
                                                     ‘signed’]  result
 hints:  [‘signed’] (_c188::I64)(_c189::I64, _c18a::I64, _c18b::I64);
            ...
 }}}

 Cmm does not make any forward declaration of `testCSymbol`. It just uses
 the name ad-hoc, assigning it to the `c188` variable, eventually calling
 that variable at the proper type. This makes it nontrival to infer
 `testCSymbol`'s type (probably undecidable, considering anything can
 theoretically happen to these variables).

 It seems to me that Cmm needs to outlaw implicit declarations of foreign C
 symbols, `EFF_` needs to be removed, and there needs to be a local extern
 declaration syntax in Cmm.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14647>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list