Skip to content

Wrong short representation using FFI on M1 macbook with GHC 8.10.7 with optimizations

Summary

When calling a c function using the ccall api on M1 macs and passing it an Int16, the value is represented as if it is an unsigned short int instead of a short int, when compiling with optimizations.

Steps to reproduce

Code

  • code.c:
#include <stdio.h>

short int func(short int targetType)
{
  printf("%d\n", targetType);
  return (-1);
}
  • main.hs:
{-# LANGUAGE ForeignFunctionInterface #-}

module Main where

import Data.Int

foreign import ccall "code.h func" func :: Int16 -> IO Int16

main :: IO ()
main = do
  res <- func (-2)
  print res

Compiling and running

With optimizations (bug)

$ ghc main.hs code.c -O
$ ./main
65534
-1

Without optimizations (correct)

$ ghc main.hs code.c
$ ./main
-2
-1

Expected behavior

With optimizations should work the same as without optimizations.

Environment

  • GHC version used: 8.10.7 arm64
  • cabal-install 3.4.0.0
  • LLVM 13.0.0

Optional:

  • Operating System: MacOS 12.0.1
  • System Architecture: M1 chip (a.k.a. arm64, a.k.a. aarch64?)

Original ticket before the minimal reproduction steps. There are more interesting details here!

Summary

I've tried using the fpco/odbc library on M1 and ran into issues when crossing the boundary between Haskell and C. To me this seem like a compiler bug, but let me know if you think differently.

More details, reproduction steps and some debugging thoughts in the fpco/odbc issue #41 thread, including the behavior change when run with traceShowId and the output of printing targetType in the C layer.

This warning emitted when compiling the project also seems like a relevant suspect:

/var/folders/4p/vsznhmbx6p15bndr9g1fwv3m0000gn/T/ghc3543_0/ghc_1.s:354:2: error:
     warning: instruction movi.2d with immediate #0 may not function correctly on this CPU, converting to equivalent movi.16b
            movi.2d v0, #0000000000000000
            ^
    |
354 |         movi.2d v0, #0000000000000000
    |  ^

Steps to reproduce

Described in the fpco/odbc issue #41 thread. The gist is:

Compile the odbc project

$ git clone https://github.com/fpco/odbc
$ cabal v2-build odbc

Run MSSQL with docker

$ docker run --name odbc-test-21433 --platform linux/arm64 -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=hUntEr202 -p 127.0.0.1:21433:1433 -d mcr.microsoft.com/azure-sql-edge

Run the odbc exec

$ cabal v2-run odbc -- 'DRIVER={ODBC Driver 17 for SQL Server};SERVER=192.168.0.146,21433;Uid=sa;Pwd=hUntEr202;Encrypt=no'
> CREATE TABLE mytest (a text);
Rows: 0
> insert into mytest values('abc');
Rows: 0
> select * from mytest;
UnsuccessfulReturnCode "getSize" (-1) "[unixODBC][Driver Manager]Program type out of range[unixODBC][Driver Manager]Program type out of range"
> select * from mytest;
[row 0]
a: "abc"

Rows: 1

This can be reproduced after restarting the odbc executable and running select * from mytest; again.

Expected behavior

select * from mytest; should not fail, and return the same output it returned on the second run.

Edited by Gil Mizrahi
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information