1

I have question regarding how to correctly handle association (or depedency) in JNI.

Lets assume that in your shared library you have 2 classes, NativeClass1 and NativeClass2. NativeClass1 has a method void fooNative(NativeClass2* nativeObj) which allows it to perform some operation with an object of type NativeClass2.

For each of these classes, a java class is defined to wrap the corresponding native object (JavaClass1 and JavaClass2, each one having a long private member pointing to a dynamically allocated native object of type NativeClass1and NativeClass2, respectively).

I would like JavaClass1 to also have a method public void fooJava(JavaClass2 obj) (and a corresponding native method private native void call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr) which will eventually call NativeClass1::void fooNative(NativeClass2* nativeObj) after casting the pointers).

How you would get the underlying long pointer (to a NativeClass2) member from JavaClass2 in order to call void JavaClass1::call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr) ( assuming you pass a pointer of to NativeClass1 as the first parameter)?

I thought of 2 methods:

  1. Creating a public getter method for the long pointer from JavaClass2.

But everybody could have access to the actual native object, create another shared library, perform a delete ptr on the void pointer of NativeClass2 or damage the native ojbect in some other way.

  1. Instead of passing the pointer to the NativeClass2 object (as the second parameter from call_fooNative(...), pass the actual java object of type JavaClass2 and determine the pointer with getFieldId and getLongField (which is permited on a private member, as stated in The Java Native Interface: Programmer's Guide and Specification By Sheng Liang, "10.9 Violating Access Control Rules".

Which one would be the correct way in terms of design and security?

1 Answers1

0

How you would get the underlying long pointer (to a NativeClass2) member from JavaClass2 in order to call void JavaClass1::call_fooNative(long nativeObject1Ptr, long nativeObject2Ptr) (assuming you pass a pointer of to NativeClass1 as the first parameter)?

Your first method can be reasonable. It's the method used by SWIG.

SWIG is an open-source tool that generates Java wrappers for C++ code. If you're wrapping a lot of classes or methods, you may want to consider using it.

For example, here's some code generated by SWIG (with the class name changed):

public class Foo {
  private long swigCPtr;
  protected boolean swigCMemOwn;

  public Foo(long cPtr, boolean cMemoryOwn) {
    swigCMemOwn = cMemoryOwn;
    swigCPtr = cPtr;
  }

  public static long getCPtr(Foo obj) {
    return (obj == null) ? 0 : obj.swigCPtr;
  }

  ...

But everybody could have access to the actual native object, create another shared library, perform a delete ptr on the void pointer of NativeClass2 or damage the native object in some other way.

Not necessarily everybody -- just Java and native code that has access to a reference to a particular instance of NativeClass2.

  1. Instead of passing the pointer to the NativeClass2 object (as the second parameter from call_fooNative(...), pass the actual java object of type JavaClass2 and determine the pointer with getFieldId and getLongField ...

This won't necessarily prevent access to the pointer from Java. Java code can use reflection to access private fields.

Community
  • 1
  • 1
Andy Thomas
  • 84,978
  • 11
  • 107
  • 151