Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ccall fails to pass/return struct{char, char} #14204

Closed
maleadt opened this issue Dec 1, 2015 · 6 comments
Closed

ccall fails to pass/return struct{char, char} #14204

maleadt opened this issue Dec 1, 2015 · 6 comments

Comments

@maleadt
Copy link
Member

maleadt commented Dec 1, 2015

Messing around with the ccall test suite, I came across this test failure on x86_64:

test.c (compile using clang -g -fPIC -shared -Wall test.c -o test.so):

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

typedef struct {
    char x;
    char y;
} struct10;

struct10 test(struct10 a)
{
    fprintf(stderr,"%" PRId8 ",%" PRId8 "\n", a.x, a.y);
    a.x += 1;
    a.y -= 2;

    return a;
}

test.jl:

using Base.Test

type Struct10
    x::Char
    y::Char
end

let
    a = Struct10('a', 'b')

    x = ccall((:test, "./test.so"), Struct10, (Struct10,), a)

    @test x.x == a.x+1
    @test x.y == a.y-2
end

This yields:

$ julia test.jl
97,0
Test Failed
  Expression: x.x == a.x + 1
   Evaluated: '﹢' == 'b'

The struct is passed incorrectly to the C function, printing 97,0 instead of 97,98. Analyzing the ccall signature, julia seems to bitcast the struct to a i64 while clang generates a coerced i16 parameter (however, having a quick look in the debugger I couldn't spot the 'b' anywhere in memory). The return value is also botched.

This is on a haswell x86_64, with julia from git master built using LLVM 3.7, but it also fails on 0.4 from the Arch repositories.

@tomaklutfu
Copy link
Contributor

Does using Cchar in Struct10 make difference? Char is 4 bytes and Cchar 1 byte.

@maleadt
Copy link
Member Author

maleadt commented Dec 1, 2015

Yes, works fine when using Cchar instead. I didn't expect that, as passing Char directly does work properly. Looking at the IR, I assume ccall converts the types automatically, while the struct just gets bitcasted.

@tomaklutfu
Copy link
Contributor

I think type Char in julia and char in C different bittypes. For equivalence, Cchar is the correct one to use in Julia. You can check the size of Struct10 with sizeof. If Char used the size is 8 bytes, else Cchar used the size is 2 bytes (equivalently i64 and i16)

@yuyichao
Copy link
Contributor

yuyichao commented Dec 1, 2015

Yes, you should use Cchar. See the doc for a complete list. Passing Char in ccall directly probably works because of the calling convention.

@yuyichao yuyichao closed this as completed Dec 1, 2015
@maleadt
Copy link
Member Author

maleadt commented Dec 1, 2015

OK thanks. I had the impression some conversions happened automatically, because of how often this actually leads to functional code. Sorry for the noise!

@tomaklutfu
Copy link
Contributor

Conversion happens if ccall is instructed to but you tell ccall that argument type is Struct10 and type of 'a' is Struct10 so no conversion is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants