[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