Skip to content

Wrong size for int for callbacks into Haskell from foreign code

The following code produces different results on amd64 (64-bit little endian) and s390x (64-bit big endian).

foo.h:

typedef void(*hs_callback)(int x);
extern void function_in_c(hs_callback cb);

foo.c:

#include "foo.h"

void function_in_c(hs_callback cb)
{
    int x = 10;
    cb(x);
}

Foo.hs:

module Main(main) where

import Foreign
import Foreign.C

type HsCallback = CInt -> IO ()

foreign import ccall "foo.h function_in_c"
  functionInC :: FunPtr HsCallback -> IO ()

foreign import ccall "wrapper"
  wrap :: HsCallback -> IO (FunPtr HsCallback)

main = do
  f <- wrap $ \x -> print x
  functionInC f
  freeHaskellFunPtr f

On amd64 the output is 10, but on s390x is 0. On both machines, sizeOf (undefined :: CInt) == sizeof(int) == 4. When changing HsCallback to:

type HsCallback = Int -> IO ()

both produce the same, correct result, but the above seems wrong, as sizeOf (undefined :: Int) == 8.

This has been reproduced with both ghc-8.4 and ghc-8.2, and causes dbus to fail to build on s390x (https://github.com/rblaze/haskell-dbus/issues/26), as it relies on libxml-sax which contains the above (simplified) code.

Trac metadata
Trac field Value
Version 8.4.3
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler (FFI)
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information