Name: jl125535 Date: 03/19/2004
FULL PRODUCT VERSION :
java version "1.4.2_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_04-b05)
Java HotSpot(TM) Client VM (build 1.4.2_04-b05, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux version 2.4.20-30.9 (###@###.###) (gcc version 3.2.2
20030222 (Red Hat Linux 3.2.2-5)) #1 Wed Feb 4 20:44:26 EST 2004
A DESCRIPTION OF THE PROBLEM :
I wrote a Java Native Interface definition which was embedded in a package rather than being part of the unnamed namespace. When I called a JNI entry point, the slared library file loaded but the loader was not able to find the entry point. A separate C program was able to load the library and call the entry point.
My JNI used to work because I did not put the interface into a package, but the compiler no longer accepts references to non-packaged classes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have included a set of test files which reproduce the problem. The files are separated by rows of dashes. I can mail you a zip file if you prefer. The instructions are contained in the first of the files.
Every time JNISmallTest.java is recompiled, the header file must be regenerated using one of these commands depending on Unix or Windows:
javah -o ${HOME}/projects/nei/c/jnitst/JNITest.h asst/JNISmallTest
javah -o c:\projects\nei\c\jnitst\JNITest.h asst.JNISmallTest
The C shared library must be compiled and linked using the adjacent Makefile. Once the C code has been compiled, the program may be run with the command</p>
java -Djava.library.path=${HOME}/projects/nei/c/jnitst asst/test/JNISmallTest
The Makefile also creates a C program which calls the shared library. Running a C program with a shared library requires that the .so file be copied into one of the shared library paths and running the <code>ldconfig</code> command to rebuild the shared library list. As an alternative, the environment variable LD_LIBRARY_PATH could be set to the directory where the .so file is located.
At this point, the command: ./TestMain
will run the C program which calls the NoArgs entry point in the shared library. Success shows that the shared library has been compiled properly enough that the loader can find the NoArgs entry point, at least from a C program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected that the program would print the return value of 5 from the C method.
When I called the program from the C text program, the result was:
apollo.243% TestMain
Calling NoArgs from C Main Program
Called NoArgs in shared C library
NoArgs returned 5 to calling C program
After NoArgs call
ACTUAL -
java -Xcheck:jni -cp ${HOME}/classes -Djava.library.path=. asst/test/JNITest
Calling NoArgs to set i
Exception in thread "main" java.lang.UnsatisfiedLinkError: NoArgs
at asst.test.JNISmallTest.NoArgs(Native Method)
at asst.test.JNISmallTest.main(JNISmallTest.java:105)
NOTE: The java library path may or may not include . by default. If JVM cannot load the library, the above command results in an unsatisfied link error for the JNITest library as a whole:
java -Xcheck:jni -cp ${HOME}/classes -Djava.library.path=/ asst/test/JNITest
Exception in thread "main" java.lang.UnsatisfiedLinkError: no JNITest
in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)
at java.lang.Runtime.loadLibrary0(Runtime.java:788)
at java.lang.System.loadLibrary(System.java:834)
at asst.test.JNISmallTest.<clinit>(JNISmallTest.java:142)
but not finding the library is clearly different from finding the library but not finding the NoArgs entry point.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
See Above
REPRODUCIBILITY :
This bug can be reproduced always.
-------------------------------------------------------
/* @name JNISmallTest.java*/
package asst.test;
public class JNISmallTest {
public JNISmallTest() {
}
public static void main (String[] args) {
int i;
System.err.println("Calling NoArgs to set i");
i = JNISmallTest.NoArgs();
System.err.println("No args " + i);
}
/** No-arg native method to test the simple case. */
public static native int NoArgs();
static {
try {
System.loadLibrary("JNITest");
} catch (Exception e) {
System.out.println("Load exception " + e.toString());
e.printStackTrace();
}
}
}
-------------------------------------------------------
/* @name JNITest.c */
#define JNITest_c
static char rcsid[] = "$Id:$";
#include <stdio.h>
#include <stdlib.h>
#include "JNITest.h"
JNIEXPORT jint JNICALL Java_asst_0002ftest_0002fJNISmallTest_NoArgs
(JNIEnv * env, jclass cls) {
printf("Called NoArgs in shared C library\n");
return 5;
}
-------------------------------------------------------
/* @name TestMain.c */
#define testmain_c
static char rcsid[] = "$Id: TestMain.c,v 1.4 2004/03/16 20:20:54 nei
Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("Calling NoArgs from C Main Program\n");
printf("NoArgs returned %d to calling C program\n",
Java_asst_0002ftest_0002fJNISmallTest_NoArgs(0, 0));
printf("After NoArgs call\n");
exit(0);
}
-------------------------------------------------------
# Make file to compile the test JNI code. Documentation is in the
# file JNISmallTest.java.
CC = gcc
CFLAGS += -g -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
LDFLAGS += -g -fPIC
all: libJNITest.so TestMain
%.o : %.c
$(CC) $(CFLAGS) -c $<
JNITest.o: JNITest.c JNITest.h
libJNITest.so: JNITest.o
$(CC) $(LDFLAGS) -shared -W1 --soname=$@ $< -o $@
TestMain: TestMain.o
$(CC) $(LDFLAGS) -L. -lJNITest $< -o $@
-------------------------------------------------------
#include <jni.h>
/* Header for class asst_0002ftest_0002fJNISmallTest */
#ifndef _Included_asst_0002ftest_0002fJNISmallTest
#define _Included_asst_0002ftest_0002fJNISmallTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: asst_0002ftest_0002fJNISmallTest
* Method: NoArgs
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_asst_0002ftest_0002fJNISmallTest_NoArgs
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I have kept my VERY OLD Java compiler and I compile the affected classes with it. The new compiler documentation says that the .class files will work with the new compiler for a while, but this is extremely troublesome.
(Incident Review ID: 243814)
======================================================================
###@###.### 10/5/04 22:30 GMT
FULL PRODUCT VERSION :
java version "1.4.2_04"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_04-b05)
Java HotSpot(TM) Client VM (build 1.4.2_04-b05, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux version 2.4.20-30.9 (###@###.###) (gcc version 3.2.2
20030222 (Red Hat Linux 3.2.2-5)) #1 Wed Feb 4 20:44:26 EST 2004
A DESCRIPTION OF THE PROBLEM :
I wrote a Java Native Interface definition which was embedded in a package rather than being part of the unnamed namespace. When I called a JNI entry point, the slared library file loaded but the loader was not able to find the entry point. A separate C program was able to load the library and call the entry point.
My JNI used to work because I did not put the interface into a package, but the compiler no longer accepts references to non-packaged classes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I have included a set of test files which reproduce the problem. The files are separated by rows of dashes. I can mail you a zip file if you prefer. The instructions are contained in the first of the files.
Every time JNISmallTest.java is recompiled, the header file must be regenerated using one of these commands depending on Unix or Windows:
javah -o ${HOME}/projects/nei/c/jnitst/JNITest.h asst/JNISmallTest
javah -o c:\projects\nei\c\jnitst\JNITest.h asst.JNISmallTest
The C shared library must be compiled and linked using the adjacent Makefile. Once the C code has been compiled, the program may be run with the command</p>
java -Djava.library.path=${HOME}/projects/nei/c/jnitst asst/test/JNISmallTest
The Makefile also creates a C program which calls the shared library. Running a C program with a shared library requires that the .so file be copied into one of the shared library paths and running the <code>ldconfig</code> command to rebuild the shared library list. As an alternative, the environment variable LD_LIBRARY_PATH could be set to the directory where the .so file is located.
At this point, the command: ./TestMain
will run the C program which calls the NoArgs entry point in the shared library. Success shows that the shared library has been compiled properly enough that the loader can find the NoArgs entry point, at least from a C program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expected that the program would print the return value of 5 from the C method.
When I called the program from the C text program, the result was:
apollo.243% TestMain
Calling NoArgs from C Main Program
Called NoArgs in shared C library
NoArgs returned 5 to calling C program
After NoArgs call
ACTUAL -
java -Xcheck:jni -cp ${HOME}/classes -Djava.library.path=. asst/test/JNITest
Calling NoArgs to set i
Exception in thread "main" java.lang.UnsatisfiedLinkError: NoArgs
at asst.test.JNISmallTest.NoArgs(Native Method)
at asst.test.JNISmallTest.main(JNISmallTest.java:105)
NOTE: The java library path may or may not include . by default. If JVM cannot load the library, the above command results in an unsatisfied link error for the JNITest library as a whole:
java -Xcheck:jni -cp ${HOME}/classes -Djava.library.path=/ asst/test/JNITest
Exception in thread "main" java.lang.UnsatisfiedLinkError: no JNITest
in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)
at java.lang.Runtime.loadLibrary0(Runtime.java:788)
at java.lang.System.loadLibrary(System.java:834)
at asst.test.JNISmallTest.<clinit>(JNISmallTest.java:142)
but not finding the library is clearly different from finding the library but not finding the NoArgs entry point.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
See Above
REPRODUCIBILITY :
This bug can be reproduced always.
-------------------------------------------------------
/* @name JNISmallTest.java*/
package asst.test;
public class JNISmallTest {
public JNISmallTest() {
}
public static void main (String[] args) {
int i;
System.err.println("Calling NoArgs to set i");
i = JNISmallTest.NoArgs();
System.err.println("No args " + i);
}
/** No-arg native method to test the simple case. */
public static native int NoArgs();
static {
try {
System.loadLibrary("JNITest");
} catch (Exception e) {
System.out.println("Load exception " + e.toString());
e.printStackTrace();
}
}
}
-------------------------------------------------------
/* @name JNITest.c */
#define JNITest_c
static char rcsid[] = "$Id:$";
#include <stdio.h>
#include <stdlib.h>
#include "JNITest.h"
JNIEXPORT jint JNICALL Java_asst_0002ftest_0002fJNISmallTest_NoArgs
(JNIEnv * env, jclass cls) {
printf("Called NoArgs in shared C library\n");
return 5;
}
-------------------------------------------------------
/* @name TestMain.c */
#define testmain_c
static char rcsid[] = "$Id: TestMain.c,v 1.4 2004/03/16 20:20:54 nei
Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("Calling NoArgs from C Main Program\n");
printf("NoArgs returned %d to calling C program\n",
Java_asst_0002ftest_0002fJNISmallTest_NoArgs(0, 0));
printf("After NoArgs call\n");
exit(0);
}
-------------------------------------------------------
# Make file to compile the test JNI code. Documentation is in the
# file JNISmallTest.java.
CC = gcc
CFLAGS += -g -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
LDFLAGS += -g -fPIC
all: libJNITest.so TestMain
%.o : %.c
$(CC) $(CFLAGS) -c $<
JNITest.o: JNITest.c JNITest.h
libJNITest.so: JNITest.o
$(CC) $(LDFLAGS) -shared -W1 --soname=$@ $< -o $@
TestMain: TestMain.o
$(CC) $(LDFLAGS) -L. -lJNITest $< -o $@
-------------------------------------------------------
#include <jni.h>
/* Header for class asst_0002ftest_0002fJNISmallTest */
#ifndef _Included_asst_0002ftest_0002fJNISmallTest
#define _Included_asst_0002ftest_0002fJNISmallTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: asst_0002ftest_0002fJNISmallTest
* Method: NoArgs
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_asst_0002ftest_0002fJNISmallTest_NoArgs
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I have kept my VERY OLD Java compiler and I compile the affected classes with it. The new compiler documentation says that the .class files will work with the new compiler for a while, but this is extremely troublesome.
(Incident Review ID: 243814)
======================================================================
###@###.### 10/5/04 22:30 GMT