Java/JVM: call native C method using it's address and signature - java

Let's say I have a C function
int32_t add(int32_t a, int32_t b) { return a + b; }
located at the address long funcAddr in my JVM process memory. Is there any way to call it from the Java code?
In python you can initialize a CFUNCTYPE instance from an integer. I'm looking for exactly the same functionality.
I found this proposal, but it doesn't seem to have been implemented in JVM.
My use case is that I generate a function using LLVM and want to execute it afterwards.

Following the advices in the comments, I used JNA 5.4.0 to invoke the function like this
Function f = Function.getFunction(new Pointer(funcAddr), 0, "utf8");
long result = f.invoke(Long.class, long[]{1, 2});
// result == 3

Related

"Invalid memory access" when calling Delphi DLL from Java

We have a DLL, written in Delphi, being called by a Java app. Initially we had issues when using PChar or ShortString but we changed these to PAnsiChar and all our issues seemed to have been solved.
However, when we started deploying the DLL to our clients, about 50% of the installations get the following error: Invalid memory access.
The very first line in the DLL is to write to our log file but that is not happening which indicated there is a problem between the Delphi and Java datatypes. Does anybody have any ideas as to what Delphi and Java data types work well together?
Delphi DLL code:
function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
WriteLog('HasCOMConnection: DLL entered');
Result := HasConnection(COMServerName);
end;
exports
HasCOMConnection;
Calling from Java:
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(String COMServerName);
}
private boolean canConnectToCOMServer() {
try {
IPMOProcessLabResult lib = (IPMOProcessLabResult) Native.loadLibrary(config.libraryName, IPMOProcessLabResult.class);
return lib.HasCOMConnection(config.comServerName);
}
catch (Exception ex) {
new AppendLog(new Date(), this.getClass() + "\t" + ex.getClass() + "\t" + "Exception while trying to connect to COMServer: " + ex.getMessage(), "debug");
return false;
}
}
Per the Java JNA documentation, a Java String is converted to a const char* when passed to native code:
Java Strings perform the same function as the native types const char* and const wchar_t* (NUL-terminated arrays). In order to use the proper type when calling a native function, we have to introduce some sort of annotation to identify how the java Stringshould be converted. Java Strings are normally converted to char* since this is the most common usage of strings. Strings are automatically converted to a NUL-terminated array of characross the function call. Returned char* values are automatically copied into a String if the method signature returns String (strdup, for example).
So the use of PAnsiChar on the Delphi side is correct when passing a String as-is.
However, Delphi strings in Delphi 2009+ are natively encoded in UTF-16, same as Java strings. So, it would be more efficient (or at least, no risk of data loss) to use WString on the Java side:
The WString class is used to identify wide character strings. Unicode values are copied directly from the Java char array to a native wchar_t array.
And use PWideChar on the Delphi side to match, eg:
function HasCOMConnection(COMServerName: PWideChar): Boolean; stdcall;
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(WString COMServerName);
}
That being said, there are 2 other problems with your code.
Per the same JNA documentation, a Java boolean maps to a native int, not a bool, so your Delphi code needs to use Integer (or Int32) or better LongBool, eg:
function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; stdcall;
More importantly, if a native library uses the stdcall calling convention, you have to extend IPMOProcessLabResult from com.sun.jna.win32.StdCallLibrary, eg:
private interface IPMOProcessLabResult extends com.sun.jna.StdCallLibrary
Otherwise, if you extend from com.sun.jna.Library then you need to use cdecl on the native side:
function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; cdecl;

Android Tracing a Java API back to jni

I'm trying to understand the interaction between the java and jni, so I decided to trace one of the java API, public int write (byte[] audioData, int offsetInBytes, int sizeInBytes) (https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r1/media/java/android/media/AudioTrack.java#1699).
If someone would point out if my thought process is correct or not.
The method
public int write (byte[] audioData, int offsetInBytes, int sizeInBytes)
contains
return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);
so it can be traced back to
public int write(#NonNull byte[] audioData, int offsetInBytes, int sizeInBytes, #WriteMode int writeMode)
(https://android.googlesource.com/platform/frameworks/base/+/android-6.0.1_r1/media/java/android/media/AudioTrack.java#1739).
Inside that function, it has
int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat, writeMode == WRITE_BLOCKING);
which calls the native method
private native final int native_write_byte(byte[] audioData,i nt offsetInBytes, int sizeInBytes, int format, boolean isBlocking);
After I grep through all of the AOSP, I found that the only place that contains native_write_byte is in static JNINativeMethod gMethods[]
`"native_write_byte", "([BIIIZ)I",
(void*)android_media_AudioTrack_writeArray<jbyteArray>`
(`https://android.googlesource.com/platform/frameworks/base/+/android-
6.0.1_r1/core/jni/android_media_AudioTrack.cpp#1065`)
(`https://android.googlesource.com/platform/frameworks/base/+/android-
6.0.1_r1/core/jni/android_media_AudioTrack.cpp#592`)
Now I want to find in which shared objects contains the native function, so I downloaded all of the files in /system/bin and grep through them, and only found one which is libandroid_runtime.so.
After opening the shared object in Ida pro, I found it by searching for the unique string.
So I'm thinking that when developers use the write function, they import libandroid_runtime.so and use write function which contains native_write_byte function which is a native function that calls to static jint android_media_AudioTrack_writeArray.
Is this the right way to trace back to the C++?
You did most of the work correctly.
I don't know why you stopped at android-6.0.1_r1, the same CPP file is available in master. This native method is implemented as a template specialization of a C++ function:
template <typename T>
static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
T javaAudioData,
jint offsetInSamples, jint sizeInSamples,
jint javaAudioFormat,
jboolean isWriteBlocking) {
You can study how this function works. Note that here, as typical for Android platform code, the JNI calls are wrapped with nativehelper headers.
to find in which shared objects contains the native function, you can look up the corresponding Android.bp script.
cc_library_shared {
name: "libandroid_runtime",
...
srcs: [
...
"android_media_AudioTrack.cpp",
grep through /system/bin is not necessary, and could actually be misleading, especially if the library were built with obfuscation turned on.
So I'm thinking that when developers use the write function, they import libandroid_runtime.so and use write function which contains native_write_byte function which is a native function that calls to static jint android_media_AudioTrack_writeArray.
Basically correct. In Java, we usually invoke System.loadLibrary(name) to import libname dynamic library, and we would say «native_write_byte is implemented with static jint android_media_AudioTrack_writeArray<jbytearray>()» rather than speak about a call from native_write_byte.
Android runtime is a bit different. It is started on system load and reused by all apps. This start invokes, among others, register_android_media_AudioTrack(JNIEnv *), and that registers all native methods listed in the gMethods table which belongs to android_media_AudioTrack.cpp.

How to run lisp scripts by passing arguments from Java

I am trying to run lisp scripts by passing arguments from Java.
For eg:
In the below script, the value of x should be passed from Java code.
(defun double (x) (* x 2))
Could you please give some examples?
If you are interested in Common Lisp there probably are many implementation. One I know of is Armed Bear Common Lisp and according to their user documentation you can mix host code (eg. Java libraries and classes) and CL code.
Running Lisp code from Java:
Interpreter interpreter = Interpreter.createInstance();
interpreter.eval("(load \"my-lisp-code.lisp\")");
Symbol myFunctionSym =
defaultPackage.findAccessibleSymbol(
"MY-FUNCTION");
Function myFunction =
myFunctionSym.getSymbolFunction();
Cons list =
(Cons) myFunction.execute(
Fixnum.getInstance(64),
Fixnum.getInstance(64));
Calling Java from Common Lisp:
public class Main {
public int addTwoNumbers(int a, int b) {
return a + b;
}
}
(defun void-function (param)
(let* ((class (jclass "Main"))
(intclass (jclass "int"))
(method (jmethod class "addTwoNumbers" intclass intclass))
(result (jcall method param 2 4)))
(format t "in void-function, result of calling addTwoNumbers(2, 4): ~a~%" result)))
The Lisp Wiki page about CL and Java integration has other solutions as well. I especially have hopes for Cloak. As ABCL implements CL running on JVM, Cloak seem to implement JVM under SBCL.

SiUSBxp.dll + JNA

I am trying to use siUSBxp.dll with java using(JNA) generally every thing fine
but I have problem with SI_CheckRXQueue sometimes it is working fine but sometimes give
"QueueStatus = SI_RX_NO_OVERRUN)" this problem happens only in java
I tried to use same function in c++ it is always working correctly but in java most of the times give me "Queue-status = SI_RX_NO_OVERRUN" and NumBytesInQueue, =0
This is java implementation using JNA :
int SI_CheckRXQueue (HANDLE Handle, IntByReference NumBytesInQueue,IntByReference QueueStatus);
This is native C siUSBxp.dll code
SI_STATUS SI_CheckRXQueue (HANDLE Handle, LPDWORD NumBytesInQueue,LPDWORD QueueStatus)
could you please help me to

Error with jni (java6) and X25 native code (C language) when code uses system call "connect()" on Solaris 5.9

In past years, we created a program that uses X25 protocol. It was made in C language and works fine for a Sun-Fire machine with Solaris 5.9.
Recently, we are working with java 6 in same machine, and we are trying to adapt that old program in C for working with java via jni.
So I have done some modifications to the old C program and created a shared library named x25lib.so
But I have found a runtime problem using jni and X25: When the C function is invoked from java via jni, the C code does not work in a same way that when it is invoked from another C program.
Concrete, using jni, the C code in shared library works fine until is invoked the system call connect(), then returns -1,
But invoking the same C code of my shared library from another C program returns 0 (ok)
In both cases, the C code in shared library doesn´t receive external parameters so the conditions are the same, I don´t understand if loading my "x25lib.so" shared library from java have a little difference that induce connect() in C fails.
using "truss" command from java I have found the error:
/2: connect(5, 0xFD878B75, 112, 1) Err#22 EINVAL
the same, but invoking the shared lib from another C program:
connect(4, 0xFFBFE794, 114, 1) = 0
So it works ok only with pure C,
Is there another consideration for using jni and X25 for solaris 5.9?
IMPORTANT: C Code in shared library is identical in both cases.
COMPILATION TIME:
a. Creating x25lib.so
cc -w -fd -G -Kpic subs.o -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib -lsockx25
-lsocket -lnsl -I"/SDK/jdk/include/" -I"/SDK/jdk/include/solaris/"
-o x25lib.so -h x25lib.so x25jni.c
b. Creating a test C program with that shared library:
cc -w x25lib.so -o x25test x25test.c
where `x25test.c` contains:
#include <stdio.h>
main()
{
java_x25();
}
c. Using java:
public class X25 {
static {
System.load("/home/x25lib.so");
}
public native void ejecutaComando();
}
public class TestX25 {
public static void main(String ... args) {
X25 x25 = new X25();
x25.ejecutaComando();
}
}
Then in C code shared library:
/*
* Class: X25
* Method: ejecutaComando
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_X25_ejecutaComando
(JNIEnv *env, jobject obj)
{
java_x25();
}
So finally both programs (java y C) call exactly the same C code in shared library:
java_x25()
Without parameters, so execute the same code.
Why works fine when is called from C, but fails when is called from java?
Thanks for any advice.
Thanks for your comments. I have found a solution while I was trying another approach: I decided not using jni, instead I adapted the old C program for listening for simple tcp connections from java and then could execute x25 code, but surprise, I got the same runtime error like using jni:
connect(5, 0xFD8789C5, 112, 1) Err#22 EINVAL
including a size of 112 instead 114, it was the same problem.
So I noticed that the problem was that I had compiled the new C program with "-lsocket" option before "-lsockx25", so that was a clue. Then I searched in google and I found a similar problem:
link to java X25 Bug ID:4077576
At the end of that article, it is mentioned the option LD_PRELOAD to force sockx25 library be loaded first. Finally the solution was at runtime:
bash$ export LD_PRELOAD=/opt/SUNWconn/lib/libsockx25.so
bash$ java TestX25
and then all is working fine using jni.
Reference for LD_PRELOAD: link to java tuning
Some observations (please post your code if you would like us to go deeper on this -- in particular the part that sets up the parameters to connect()):
Assuming X.25 over TCP(?):
From the man page EINVAL is returned from connect(3socket) "namelen is not the size of a valid address for the specified address family" where namelen is the sockaddr structure defined in <sys/socket_impl.h>. namelen is typically 16 (a 2-byte address family (I'd expect SOCK_STREAM) followed by 14 octets of address data). Your program returns namelen 112 or 114.
The address of name in your failing truss(1) output above 0xFD878B75 is odd (odd in the sense "not even"). Given Solaris' typical alignment requirements this seems strange. (SPARC or x86? What compiler and flags?). Perhaps a pointer or sizeof problem?
From your truss(1) output can see that threads are being used in the java invocation. Are your libraries thread-safe?

Categories

Resources