Only 4 bytes of a pointer retrieved in C

embedding

#1

Hello everybody,

I’m having a problem with a Julia function which returns a pointer to an object. The pointer is coded in 8 bytes. This function has a C interface to be used form a C program.
When I use this function in C, only the half of the value (the 4 less signicant bytes) is retrived. So, I can’t reuse the pointed object… :frowning:
For information, I am working on a 64-bit Linux

To be more explicit, here’s my Julia code

type MyType
  param1::Int
  param2::Int
  function MyType()
    new(1,2)
  end
end

Base.@ccallable function create_object()::Ptr{Void}
  newobject = MyType()
  objectpointer = pointer_from_objref(newobject)
  println("Simple object pointer :")
  print_pointer(objectpointer)
  return objectpointer
end

Base.@ccallable function print_pointer(inputpointer::Ptr{Void})::Cint
  println("pointer : ")
  println(inputpointer)
  return 0
end

Here’s my C code :

    jl_value_t* simple_ptr;
    simple_ptr = create_object();
    printf("simple object created\n");
    print_pointer(simple_ptr);

And here’s the output :

Simple object pointer :
pointer : 
Ptr{Void} @0x00007eff6e125c10
simple object created
pointer : 
Ptr{Void} @0x000000006e125c10

The generation of the shared library to be used in C is made by static-julia which execute the following commands :

  • Populate “.ji” local cache:
    $JULIA_HOME/bin/julia -Cx86-64 -J$JULIA_HOME/lib/julia/sys.so --compile=yes --depwarn=yes --startup-file=no -e

  • Build object file “julia_example.o”:
    $JULIA_HOME/bin/julia -Cx86-64 -J$JULIA_HOME/lib/julia/sys.so --compile=yes --depwarn=yes --startup-file=no --output-o julia_example.o -e

  • Build shared library “libjulia_example.so”:
    gcc -m64 -shared -o libjulia_example.so julia_example.o -std=gnu99 -I$JULIA_HOME/include/julia -DJULIA_ENABLE_THREADING=1 -fPIC -L$JULIA_HOME/lib -Wl,–export-dynamic -Wl,-rpath,/lib -Wl,-rpath,$JULIA_HOME/lib/julia -ljulia

  • Build executable file “julia_example”:
    gcc -m64 -o julia_example $JULIA_HOME/static-julia/example.c libjulia_example.so -std=gnu99 -I/include/julia -DJULIA_ENABLE_THREADING=1 -fPIC -L/lib -Wl,–export-dynamic -Wl,-rpath,/lib -Wl,-rpath,/lib/julia -ljulia ‘-Wl,-rpath,$ORIGIN’

What am I doing wrong? Is it due to a wrong compilation? the C code, the Julia code?
Thank you for your help !

Nextor


#2

This is wrong, and the returned pointer can be garbage. It’s unrelated to your issue though.

Please post the FULL C code and fix all compiler warnings. You likely declare the functions in C incorrectly.


#3

Hello yuyi !
Thank you for your answer. While I was responding to you, I found that I didn’t declare explicitely the extern functions. Indeed, when the functions are explicitely declared , it works OK.
Your answer helped me to solve my problem. Thank you very much.

Anyway, why do you say that the Julia function is wrong? Why do you say that the pointer can be garbage?
Is there any way to control garbage collector in order to avoid the object from being unreferenced?

Now, my C code is


// Standard headers
#include <string.h>
#include <stdint.h>
#include <stdio.h>

// Julia headers (for initialization and gc commands)
// #include "uv.h"
#include "julia.h"

#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia 0.7+
JULIA_DEFINE_FAST_TLS()
#endif

extern jl_value_t* create_object();
extern void print_pointer(jl_value_t*);
extern void print_object(jl_value_t*);

// main function (windows UTF16 -> UTF8 argument conversion code copied from julia's ui/repl.c)
int main(int argc, char *argv[])
{
	
    // initialization
    libsupport_init();
    // jl_options.compile_enabled = JL_OPTIONS_COMPILE_OFF;
    jl_options.image_file = "libjulia_example";
    julia_init(JL_IMAGE_JULIA_HOME);

    
    jl_value_t* simple_ptr;
    simple_ptr = create_object();
    printf("simple object created\n");
    print_pointer(simple_ptr);
    print_object(simple_ptr);


    //    JL_GC_POP();

    // Cleanup and gracefully exit
    jl_atexit_hook(0);
    return 0;
}

With a new Julia function :

Base.@ccallable function print_object(inputpointer::Ptr{Void})::Cint
  println("object my_type : ")
  retrieved_object = unsafe_pointer_to_objref(inputpointer)
  println(retrieved_object.param1)
  println(retrieved_object.param2)
  return 0
end

Thank you


#4

Julia will be able to free the memory immediately, since it can see that the object (which “holds” the memory) is no longer referenced after the call to pointer_from_objref.
You’d need some way of keeping a reference to that object in Julia.

I find it easier for Julia code to call into C code, so that the objects are still referenced in the Julia memory, rather than trying to return pointers to Julia objects to C code.


#5

Becuase the object can be free’d.

Not impossible but that’s not the the right approach. You should just return the object directly and use Any or appropriate Ref as the return/argument type instead. cfunction certainly support this so I assume @ccallable does too.


#6

Hi Yichao,
I understand your point of view. However, the reason that I am trying to do that this way is that I am reusing an existing Julia project and it have a large amonut of complex types, so it would represent a huge amount of work to translate everything to C. Besides, the C-side doesn’t need to read or handle the returned objects, but only to keep them to pass them back again as parameters.
Thus, I prefer to try with my approach.
Now, my question is : How can I safe my Julia objects to avoid them to be collected ? You say this is not impossible. May you guide me to do that. I don’t find the right way to do that.
Thank you in advance.


#7

It’s unclear what you mean. The many different julia type makes absolutely no difference.

Do what I said.


#8

Make sure they are still referenced on the Julia side (the Julia object, not a Ptr to the memory where one is/was (it can disappear when GC happens otherwise).


#9

No don’t do that.