Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-5016955

JNI call loads the .so library but cannot find the entry point. C code can.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.4.2
    • hotspot
    • x86
    • linux

      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

            ksrini Kumar Srinivasan
            jleesunw Jon Lee (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: