Type promotion in ccall arguments
I can't remember whether this has come up before, but to my surprise I've just discovered that FFI foreign import declarations don't contain enough infomration to be able to determine the correct calling convention for a given C function. Background: recently we "fixed" a bug in GHC's native code generator which was exposed by the following declaration: foreign import ccall unsafe snprintf :: CString -> CSize -> CString -> Float -> IO () the native code generator was passing the Float as a C float on the stack, but snprintf() expects a double. Half-remembering that C specifies that floats should be promoted to doubles in function call arguemts, I modified the NCG to do just this. But the C standard doesn't say this - it says that floats are promoted to doubles only for (a) functions without an ANSI prototype, and (b) vararg functions, for args after the "...". since the NCG can't possibly know whether the function in question has a prototype (this information isn't part of the FFI declaration), it has to pick a calling convention to use. Now, the reasonable thing to do is to pick the "has a prototype" calling convention, because this will be true for most libraries. But in the snprintf case above, the Haskell programmer would still have to explicitly declare the argument type to be a Double. I think something to this effect should be included in the FFI spec. Thoughts? Cheers, Simon
the native code generator was passing the Float as a C float on the stack, but snprintf() expects a double. Half-remembering that C specifies that floats should be promoted to doubles in function call arguemts, I modified the NCG to do just this. But the C standard doesn't say this - it says that floats are promoted to doubles only for
(a) functions without an ANSI prototype, and (b) vararg functions, for args after the "...".
Ha. So that explains why it sort-of worked before, since the promotion doesn't happen if there is a prototype. Well spotted. How absolutely horrible. Why do the C people have such a bizarre set of rules? J
At 13:47 +0000 14-03-2002, Julian Seward wrote:
How absolutely horrible. Why do the C people have such a bizarre set of rules?
How about "our" off-side rule? Doaitse -- __________________________________________________________________________ S. Doaitse Swierstra, Department of Computer Science, Utrecht University P.O.Box 80.089, 3508 TB UTRECHT, the Netherlands Mail: mailto:doaitse@cs.uu.nl WWW: http://www.cs.uu.nl/ tel: +31 30 253 3962 fax: +31 30 251 3791 mobile: +31 6 2880 1680 __________________________________________________________________________
I can't remember whether this has come up before, but to my surprise I've just discovered that FFI foreign import declarations don't contain enough infomration to be able to determine the correct calling convention for a given C function.
I'd say it has all the information you need - you were using it wrong.
Background: recently we "fixed" a bug in GHC's native code generator which was exposed by the following declaration:
foreign import ccall unsafe snprintf :: CString -> CSize -> CString -> Float -> IO ()
the native code generator was passing the Float as a C float on the stack, but snprintf() expects a double.
So that's how you should declare it then: foreign import ccall unsafe snprintf :: CString -> CSize -> CString -> Double -> IO ()
Thoughts?
If we don't like having to remember the C promotion rules ourselves, we could write a tool to do it for us. The ffi is supposed to be a _mechanism_ to let you call things and on which you can build more convenient layers. In this case, you can do that so there's no problem with the ffi. If you strongly disagree with this approach, I'd consider having GHC emit warnings whenever you pass a float using the C calling convention and allow the programmer to specify a "stop list" - a list of functions not to emit warnings for (presumably because they are ones they have a prototype for). -- Alastair Reid Reid Consulting (UK) Ltd
On 14-Mar-2002, Simon Marlow <simonmar@microsoft.com> wrote:
I can't remember whether this has come up before, but to my surprise I've just discovered that FFI foreign import declarations don't contain enough infomration to be able to determine the correct calling convention for a given C function.
Background: recently we "fixed" a bug in GHC's native code generator which was exposed by the following declaration:
foreign import ccall unsafe snprintf :: CString -> CSize -> CString -> Float -> IO ()
I don't see how interfacing with a varargs function as if it had a fixed prototype can ever be completely portable. C permits the calling convention to be different for varargs functions, and sometimes this is indeed desirable for efficiency: varargs functions require caller-pops argument passing convention, but known-prototype functions can use a more efficient callee-pops convention. Some C compilers have taken advantage of this. -- Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit The University of Melbourne | of excellence is a lethal habit" WWW: <http://www.cs.mu.oz.au/~fjh> | -- the last words of T. S. Garp.
participants (5)
-
Alastair David Reid -
Fergus Henderson -
Julian Seward -
S. Doaitse Swierstra -
Simon Marlow