Skip to content

Incorrect handling of Bool return value in FFI

Summary

When declaring a foreign C function with return type Bool or IO Bool, the output might be improperly read as True instead of False. The problem is fixed when using CBool from Foreign.C.Types, so please excuse me if I've just misunderstood what the FFI does in this case :-)

I've attached a set of files that reproduce a problem I encountered with a small Makefile, here is the C and Haskell code reproduced for better understanding:

int64_t foo(void)
{
    return -1LL;
}

bool test(void)
{
    return foo() > 0LL;
}

int main(void)
{
    printf("%d\n", test());
}
module Main(main) where

foreign import ccall "test"
  test :: IO Bool

main :: IO ()
main =
  print =<< test

The expected result to the call to test is false and it is indeed what is reported by the C main. However, on my machine (Linux Fedora, x86_64) the Haskell main prints True. After some investigation with gdb, I suspect this is due to the content of the %rax register being 0xff...ff00 after the call to test (i.e. the result is only stored on the last byte), which could be misinterpreted as True on the Haskell side?

Steps to reproduce

main.c

Main.hs

Makefile

test.c

test.h

test2.c

  • make Main-hs
  • make Main-C
  • ./Main-hs prints True
  • ./Main-C prints 0

Expected behavior

./Main-hs prints False

Environment

  • GHC version used: tested on 8.10.7 and 9.2.5

Optional:

  • Operating System: Fedora 37
  • System Architecture: x86_64
  • GCC: 12.2.1, using -O3
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information