How to get a pointer Ptr{T} that references a variable of type T

ccall

#1

I need to pass a Ptr{T} to a C function but pointer_from_objref returns Ptr{Void} rather than Ptr{T}… How should I do this?

In the following example, I need to pass a value of type Ptr{Foo} to the C function:

julia> struct Foo x end

julia> f = Foo(1)
Foo(1)

julia> pointer_from_objref(f)
Ptr{Void} @0x00007feff06d2ab0

#2

I found a solution… but is it the best way?

julia> convert(Ptr{Foo}, pointer_from_objref(f))
Ptr{Foo} @0x00007f2c94e27ad0

#3

If I’m not mistaken, you can also just tell ccall that the argument type is a Ptr{Void}.


#4

Yes, Ptr{Void} works. Thanks


#5

pointer_from_objref is not right and is in fact removed for immutable objects in 0.7. Just wrap it in a Ref.


#6

Ref doesn’t really work for me. I have over a thousand ccall functions generated from Clang. The method signatures contain arguments that take pointers as well as returning results as pointers. I have demonstrated the problem with a MWE here.

Basically, the wrapper functions may accept Ptr{T} arguments and so I will need to call it with a pointer to the object. The pointer_from_objref function works very well except that it loses its type. The Ref function works only if it’s used inside the wrapper function, for which I would rather not do as I would have a thousand calls to edit (or mess with Clang, which would not be a very pleasant exercise.)

If I call the wrapper function with Ref(x), it could not dispatch to the wrapper function since it expects Ptr{T}. If I change the method signature to accept a RefValue{T}) type, then method dispatch works but the ccall crashes julia.


#7

And that is it completely unsafe and can crash at any point when you put those ccalls inside a function (and is hence an error on julia 0.7). See https://github.com/JuliaLang/julia/issues/15857.


#8

That was a Clang.jl bug https://github.com/ihnorton/Clang.jl/issues/152. Please regenerate your wrapper.


#9

That’s interesting! However, the latest version of Clang still generates bad signature for me. Apparently, it does not recognize a typedef that is a pointer to a struct.

Consider this simple function:

typedef struct {
    double x;
} FOO, *FOOP;

FOOP test1(double a, double b, FOOP c);

It gets wrapped as

function test1(a::Cdouble, b::Cdouble, c::FOOP)
    ccall((:test1, test), FOOP, (Cdouble, Cdouble, FOOP), a, b, c)
end

But, it would be fine with Foo * instead:

typedef struct {
    double x;
} FOO, *FOOP;

FOO *test1(double a, double b, FOO *c);

turns into

function test1(a::Cdouble, b::Cdouble, c)
    ccall((:test1, test2), Ptr{FOO}, (Cdouble, Cdouble, Ptr{FOO}), a, b, c)
end

#10

I’ll submit an issue to Clang project for this similar bug.

Since the problem only happens at the signature, I can work around the issue by doing a global search and replace of ::T with an empty string. So the end result isn’t too bad.

Thanks for your help.