简体   繁体   中英

Is there a way to log the reason of an Invalid memory access in JNA

I have the following error when invoking Java code from C using JNA:

Native Exception in org.InvokerPackageCallback@3ba987b8
java.lang.Error: Invalid memory access
  at com.sun.jna.Native.getStringBytes(Native Method)
  at com.sun.jna.Native.getString(Native.java:2248)
  at com.sun.jna.Pointer.getString(Pointer.java:681)
  at com.sun.jna.Structure.readField(Structure.java:743)
  at com.sun.jna.Structure.read(Structure.java:605)
  at org.PackageStruct$ByReference.read(PackageStruct.java:102)
  at com.sun.jna.Structure.autoRead(Structure.java:2234)
  at com.sun.jna.Structure.conditionalAutoRead(Structure.java:576)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.convertArgument(CallbackReference.java:650)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:571)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:610)
  at com.sun.jna.Native.invokeVoid(Native Method)
  at com.sun.jna.Function.invoke(Function.java:415)
  at com.sun.jna.Function.invoke(Function.java:361)
  at com.sun.jna.Library$Handler.invoke(Library.java:265)

In my use case the C code invoke the publish_package_fct_pt function which is mapped to a Java interface method. This method has only one structure argument:

void publish_package_fct_ptr(void (*pf) (PackageStruct));

I use the following library:

public interface MyLib extends Library {
   public void publish_package_fct_ptr(InvokerPackage callback);

   public interface InvokerPackage extends Callback {
      void invoke(PackageStruct.ByReference pack);
   }
}

with the following structure definition:

public class PackageStruct extends Structure {
  public NativeLong id;
  public int type;
  public int subtype;   
  public String configuration;   
  public String name;
  public NativeLong date;

  public PackageStruct(Pointer peer) {
    super(peer);
  }

 public PackageStruct() {
   super();
 }

 protected List<String> getFieldOrder() {
    return Arrays.asList("id", "type", "subtype", "configuration", "name", "date");
 }

 public static class ByReference extends PackageStruct implements Structure.ByReference {
  public void read() {
     super.read();
  }
}

The C structure is:

struct PackageStruct {
  long id;
  int type;
  int subtype;
  const char *configuration;
  const char *name;
  long date;
};

It worked correctly before I added the configuration field, and I have the exception now. I "think" that the configuration field points to nothing, which might be the reason why I have this error.

Do you agree with my hypothesis? And is there a mean in JNA to log the com.sun.jna.Structure.readField to know for which field I have this error?

The "Invalid Memory Access" error thrown by JNA is a graceful"handling of native memory errors caught by Structured Exception Handling . So to answer the question in the title, unfortunately you can't get more details from the native side.

All you really need to know is that either You are attempting to access native memory that you do not own or Your native memory allocation failed .

Your mappings look correct, but you haven't shown the code where you actually call the publish_package_fct_ptr() method. That's where the problem probably exists. However, the fact that it's a callback points to a very common problem with JNA and callbacks, in which the memory is released before you use it so I'll hazard a guess here.

(Aside: you don't need to declare a Structure ByReference if used as a method argument. That's the default. You might also find the @FieldOrder annotation cleaner than the override of the getFieldOrder() method.)

JNA tracks its memory allocation using the Memory class. If you don't provide the Structure a pointer when you construct it, it will allocate the necessary memory and store that internally in a Memory object. This works for most uses of structures.

However, releasing the native memory is tied to Java's garbage collection. When the Structure is GC'd its internal memory object is also GC'd and as part of its finalize() execution it releases the native memory.

If the callback is the last time you reference the Structure in Java, it becomes unreachable and is eligible to be GC'd. In some cases, this could happen before the callback finishes executing, taking away that native memory allocation.

If you are using JDK 9+, using a ReachabilityFence after the callback will solve this problem. For JDK 8 and earlier, you may have to do some other code manipulation of the Structure after it's used in the callback, to ensure Java retains a reference to it (and its underlying native memory).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM