Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return by value from native function?

Tags:

java

jnr

I have the following C++ method compiled using Visual Studio 2017:

extern "C" __declspec( dllexport )
Info* __stdcall GetInfo(InfoProvider* infoProvider)
{
   static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");

   Info info = new Info();
   Info->data1 = infoProvider->data1;
   Info->data2 = infoProvider->data2;

   return info;
}

In Java code, it is mapped by Java Native Runtime using interface method with following signature:

Info GetInfo(Pointer infoProvider);

final class Info extends Struct {

    public final Signed32 data1;

    public final Signed32 data2;

    public R2VInfo(final Runtime runtime) {
        super(runtime);

        data1 = new Signed32();
        data2 = new Signed32();
    }
}

It works.

The above C++ method causes memory leak, so I would like to change it to return result by value:

extern "C" __declspec( dllexport )
Info __stdcall GetInfo(InfoProvider* infoProvider)
{
   static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");

   Info info{};
   Info.data1 = infoProvider->data1;
   Info.data2 = infoProvider->data2;

   return info;
}

I use the same Java JNR mapping:

Info GetInfo(Pointer infoProvider);

But it does not work - Access Violation. Native method is invoked, but with some dandling pointer value.

How to return by value in JNR?

like image 865
sgnsajgon Avatar asked May 14 '19 12:05

sgnsajgon


People also ask

How do you return a value from a function?

To return a value from a function, you must include a return statement, followed by the value to be returned, before the function's end statement. If you do not include a return statement or if you do not specify a value after the keyword return, the value returned by the function is unpredictable.

How do you return a value from a JavaScript function?

JavaScript provides for passing one value back to the code that called it after everything in the function that needs to run has finished running. JavaScript passes a value from a function back to the code that called it by using the return statement . The value to be returned is specified in the return keyword.

How do you return a value from a function in Python?

The Python return statement is a special statement that you can use inside a function or method to send the function's result back to the caller. A return statement consists of the return keyword followed by an optional return value. The return value of a Python function can be any Python object.

How will you return more than one value from a function?

We can return more than one value from a function by using the method called “call by address”, or “call by reference”. In the invoker function, we will use two variables to store the results, and the function will take pointer-type data. So we have to pass the address of the data.


1 Answers

JNI build around old pure K&R C to be compatible with all available compilers. Returning a structure from a function was introduced in C89 and was fully implemented significantly later with C++ standard together. Today it is still possible to find such old C compiler in many java-friendly environments like small devices or sim-cards. So I don't think that JNI would be upgraded to C89 or even C99.

For your case, I would recommend to write an additional C-code that handles calling of a library function. The code could be implemented in two ways:

  1. For the Info* __stdcall GetInfo(InfoProvider* infoProvider) you should write free-function like:
extern "C" __declspec( dllexport )
void __stdcall FreeInfo(Info* info)
{
   static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");

   delete info;
}
  1. For the Info __stdcall GetInfo(InfoProvider* infoProvider) you should write a wrapper:
extern "C" __declspec( dllexport )
void __stdcall GetInfo(InfoProvider* infoProvider, Info* info)
{
   static_assert(std::is_pod<Info>::value, "Must be Plain Old Data in order to be safely copied between DLL boundaries");

   Info infoProvider = GetInfo(infoProvider);
   info->data1 = infoProvider.data1;
   info->data2 = infoProvider.data2;
}
like image 142
Andrey Chistyakov Avatar answered Oct 05 '22 20:10

Andrey Chistyakov