10 Replies Latest reply on Jun 8, 2017 5:06 PM by Matthew Thurmaier

    java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException

    Vinod Patil Newbie

      I want to trace File object initialization event of java.io.File package using byteman so if my java program contains code as

       

      File f=new File("abc.txt");

       

      And Rule for above code snippet is written as

       

      RULE FileMonitor trace

      CLASS java.io.File

      METHOD <init>(String)

      AT RETURN

      IF TRUE

      DO traceln("Trace File");

      ENDRULE

       

      then JVM thows exception as

       

      Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException

        at java.io.File.<init>(Unknown Source)

        at sun.net.www.protocol.file.Handler.openConnection(Unknown Source)

        at sun.net.www.protocol.file.Handler.openConnection(Unknown Source)

        at java.net.URL.openConnection(Unknown Source)

        at java.net.URLClassLoader.getPermissions(Unknown Source)

        at sun.misc.Launcher$AppClassLoader.getPermissions(Unknown Source)

        at java.security.SecureClassLoader.getProtectionDomain(Unknown Source)

        at java.security.SecureClassLoader.defineClass(Unknown Source)

        at java.net.URLClassLoader.defineClass(Unknown Source)

        at java.net.URLClassLoader.access$100(Unknown Source)

        at java.net.URLClassLoader$1.run(Unknown Source)

        at java.net.URLClassLoader$1.run(Unknown Source)

        at java.security.AccessController.doPrivileged(Native Method)

        at java.net.URLClassLoader.findClass(Unknown Source)

        at java.lang.ClassLoader.loadClass(Unknown Source)

        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)

        at java.lang.ClassLoader.loadClass(Unknown Source)

        at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

       

       

      Thank you in advance,

        • 1. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
          Andrew Dinn Master

          Hi Vinod,

           

          . . .

          then JVM thows exception as

           

          Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException

            at java.io.File.<init>(Unknown Source)

            . . .

           

          I am fairly sure I know what is going wrong here but I really need to know how you are running Byteman in order to confirm that belief and to be able to advise you how to fix it. Could you please provide details of how you have started the program and how you have installed the Byteman agent. Also, is this just a normal Java SE application or are you using a module loader like OSGi or JBoss Modules (n.b. the latter is what you get if you run inside JBoss EAP). Finally, it would be helpful to know the version of Byteman and OpenJDK/Oracle Java that you are using.

           

          The error you are seeing is probably caused by the fact that the class you wish to inject code into (File) is part of the JDK runtime. That is significant because it means it gets loaded by the bootstrap class loader. When you install the Byteman agent (or, indeed, any JVMTI agent program) its classes are, by default, loaded by the system class loader. That normally means that other system classes and application classes can resolve references to Byteman classes -- they belong in the same class loader or a child class loader, respectively, and class lookup normally involves searching first the parent class loaders and then the current loader. However, this default set up means that bootstrap classes cannot see Byteman classes -- that's because the system loader is a child of the bootstrap loader.

           

          What is needed is to ensure that the Byteman classes are loaded by the bootstrap class loader. The user guide and the tutorials provide details of how to do this. In summary:

           

          • when installing Byteman into the JVM from the java command line add boot:/path/to/byteman.jar to the list of options provided to the -javaagent command line flag that follow the = separator. you will need to separate it from any other options such as script:/path/to/myscript.btm or listener:true using a , separator
          • when installing Byteman into the JVM using bminstall.sh pass option -b

           

          If you are running your program from ant or maven using BMUnit (this is the package which integrates Byteman with JUnit and TestNG) then I really do need the details requested above to resolve the problem (esp what your app is doing). BMUnit always ensures Byteman classes are loaded from the boostrap classpath following the -b/boot: model.

          • 2. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
            Vinod Patil Newbie

            Thanks Andrew,

            Problem resolved.Very nice explaination.

            • 3. Re: Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
              Andrew Dinn Master

              Hi Vinod,

              Thanks Andrew,

              Problem resolved.Very nice explanation.

               

               

              You are very welcome. I am glad you are up and running.

               

              Are you just trying out Byteman or are you trying to use it with a specific purpose in mind?

               

              If you are starting I recommend working through the tutorials linked from the Byteman project documentation page.

               

              If you have a specific result you are trying to achieve then don't hesitate to ask if you want some advice and please consider posting details of how you have used Byteman on the forum so others can see how it has helped you.

              1 of 1 people found this helpful
              • 4. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                Matthew Thurmaier Newbie

                A follow-on please. I'm trying to start BYTEMAN agent in Tomcat startup. I have the following line in the Tomcat startup:

                   JAVA_OPTS="-Dorg.jboss.byteman.verbose -Dorg.jboss.byteman.transform.all -javaagent:/usr/share/apache-tomcat/byteman/lib/byteman.jar=listener:true,port:9999,boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar -Xss256K -Xmx2048m -XX:MaxMetaspaceSize=512m"

                 

                I have tried this with variations on the theme, including JUST having "-javaagent:boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar".  The consist theme of the error is that in "catalina.server.out" I get:

                "Error opening zip file or JAR manifest missing : boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar"

                 

                NOTE: the jar is there, it is readable, it works fine when I use the listener and load rules that don't need boot visibility.

                 

                Thoughts?

                • 5. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                  Ondra Chaloupka Apprentice

                  From my experience the message says that there is some issue in finding the jar  /usr/share/apache-tomcat/byteman/lib/byteman.jar at the specified path.

                   

                  I would point down that javaagent itself has to be defined. If you say -javaagent:boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar the java tries to open jar file at path "boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar" which probably does not exist on your system.

                   

                  You need to define it like

                  -javaagent:/usr/share/apache-tomcat/byteman/lib/byteman.jar=boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar

                   

                  Is the byteman at /usr/share/apache-tomcat/byteman/lib/byteman.jar and is it really readable byteman jar (unzip -l /usr/share/apache-tomcat/byteman/lib/byteman.jar)?

                  1 of 1 people found this helpful
                  • 6. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                    Matthew Thurmaier Newbie

                    Ondra, Thanks for your reply. It got me close. Here is what I had to do:

                     

                        -javaagent:/usr/share/apache-tomcat/byteman/lib/byteman.jar=boot:/usr/share/apache-tomcat/byteman/lib/byteman.jar,listener:true

                     

                    So:

                    * as you suggested, put an "=" before "boot" instead of a comma (,) as the doc all says (and several examples say)

                    * then I changed the "=" before "listener" to a comma (,)

                     

                    Shazam. It now works.

                     

                    To your question of "are you sure its accessible", just a reminder that I had said that I know it is/was accessible because I could do other byteman rules, as long as I wasn't trying to inject into a boot class.

                     

                    At this point I am able to have the rule fire when someone invokes the File() constructor as desired.

                     

                    Again, THANK YOU!

                    • 7. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                      Matthew Thurmaier Newbie

                      Second follow-up on this... I had/have a similar problem but the resolution doesn't seem to work for me.

                       

                      I have code similar to the following in method sendFileToResponse:

                       

                      try {

                        xfile = new File(somepath);

                        inStream = new FileInputStream(xfile);

                        ....

                      } finally {

                        if(inStream != null) {

                          inStream.close();

                        }

                      ...

                      }

                       

                       

                      NOTE: the "finally" is at line 232.

                       

                      I have the following rules:

                       

                      RULE trace sendFileToResponse exit

                      CLASS ConfigurationManagerServlet

                      METHOD sendFileToResponse

                      AT EXIT

                      IF true

                      DO traceln(">>>>>>>>>>>>>>>>>>>exiting sendFileToResponse")

                      ENDRULE

                       

                      RULE cause sendFileToResponse exception1

                      CLASS File

                      METHOD <init>(String)

                      AT ENTRY

                      IF callerEquals("ConfigurationManagerServlet.sendFileToResponse", true)

                      DO traceln(">>>>>>>>>>>>>>>>>>File throwing IOException");

                         throw new java.lang.NullPointerException("byteman forcing File exception")

                      ENDRULE

                       

                       

                      RULE cause sendFileToResponse exception2

                      CLASS ConfigurationManagerServlet

                      METHOD sendFileToResponse

                      AT LINE 232

                      IF true

                      DO traceln(">>>>>>>>>>>>>>>>> in finally")

                      ENDRULE

                       

                      I get the following log output:

                       

                      >>>>>>>>>>>>>>>>>>>>entering sendFileToResponse

                      Rule.execute called for cause sendFileToResponse exception1_0

                      cause sendFileToResponse exception1 execute

                      >>>>>>>>>>>>>>>>>>File throwing IOException

                      caught ThrowException

                       

                      I do not see a subsequent message for "in finally" or "exiting sendFileToResponse".

                       

                      Any ideas why it doesn't seem to be progressing any farther?

                       

                      NOTE2: When I don't have the rule throwing the exception, I do see both of these messages. So, when the exception gets thrown, nothing else seems to happen. I don't get into the "finally" block. I don't know why.

                       

                      Thanks in advance!

                      • 8. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                        Ondra Chaloupka Apprentice

                        hm, unfortunatelly I can only say that I can observe the same behavior. Afther the exception is thrown by byteman the finally block is executed but the rule which is bound to the finally block, neither the EXIT rule is.

                         

                        I have got a quick test here

                         

                        https://github.com/ochaloup/btm-presentation/blob/master/examples/part2/try-catch-check/src/main/java/org/jboss/qa/TryFinallyCheck.java

                        https://github.com/ochaloup/btm-presentation/blob/master/examples/part2/try-catch-check/src/main/java/org/jboss/qa/TryFinallyCheck.java

                         

                        I'm not able to say if it's expected behavior (needs to be addressed by changing the rule, e.g. in some similar way as it was done for the exception) or if it's kind of bug. I would tip for the first one but this needs to be responded by adinn

                        • 9. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                          Andrew Dinn Master

                          Hi Matthew,

                           

                          Apologies for the slow response -- I have been taking a much-needed (and much-enjoyed) holiday for the last week :-) Thanks also to Ondra for covering for me while I was away.

                           

                          There is a good reason why you are not seeing any output from your 3rd rule and it is also a very bad reason which needs a bit of explanation. Before doing that I'll make two suggestions.

                           

                          First, avoid use of AT LINE rules if you can find any way to do so. In this case you might try to use a location like AT READ $inStream 2 or AT READ $inStream 3 or whatever number is needed to identify the specific access of inStream that occurs in the condition test in the finally block. n.b. to work out what is the correct value of the numeric count value for the location you just scan through the code counting, starting from 1, each of places where a reference to inStream is made (include references such as this.instream or instream.foobar() which lead to a getfield operation in the bytecode but exclude assignments such as instream = foobar or this.instream = foobar which lead to a putfield operation). When you have counted up to the read access you want to instrument put that number into the rule. Unfortunately, that's not necessarily going to work here because you are injecting into a finally block (yeah, we'll come to that).

                           

                          Second, if you must use an AT LINE rule then try to pick a line number that has an executable expression/statement on it. In your example code line 232 only contains the keyword finally which doesn't compute anything. Line 233 is a better choice because it includes code which computes the condition and then branches one way or the other. Unfortunately, that still is not enough to make AT LINE work here because you are injecting into a finally block ...

                           

                          Ok, I guess I really had better explain this properly. The root problem here is that bytecode is not source code. Byteman tries to pretend that bytecode is source code as far as possible by mapping the source level descriptions you provide in the AT specification to corresponding points in the bytecode. Unfortunately, the way bytecode is generated means that it cannot always do what you ask. So, when your rule asks for AT LINE 232 Byteman will track line numbers as it works its way through the bytecode and when it reaches a bytecode whose associated line number is equal to or greater than 232 it will  inject the rule code at that point. Unfortunately, that is not good enough when the code you want is in a finally block because a finally block includes code that needs to be executed on two or more different paths.

                           

                          When javac translates your example source code to bytecode it will insert two sections of bytecode to implement the code you provided in your finally block, one on the normal  path out of the try block and one in a catch-all exception handler. Yes, I know, your code doesn't include a catch-all handler (catch Throwable). However, javac adds one so it can make sure that the finally code really does get run if, say, a NullPointerException, a RuntimeException or an Error happens inside the try block. When Byteman tries to inject your 3rd rule it will spot line number 232 associated with the first bytecode section implementing the finally block and inject your rule there. At that point it sees that it has reached line 232 and decides that its work is done. It cannot recognize that the second section of bytecode included in the catch-all block is also associated with line 232 because the line number table doesn't include enough information for it to know that this is a second copy came and that it came from the same place. That explains why you see the message when the exception is not thrown but don't see it when the exception is thrown.

                           

                          The same thing explains why using AT READ $inStream N (where N is the lexical index of the desired access) is not sufficient. This will successfully inject the rule into the normal path copy of the finally code but not into the catch-all path copy. Of course, if you play around with different values of N you can inject into the 2nd bytecode sequence which implements condition instream != null and make it work -- but it's not exactly very user-friendly.  Let's assume that the reference in the condition is, say, the 3rd read of inStream in lexical order (i.e. the omitted code only makes one other reference to inStream. So, injecting AT READ $inStream 3 will inject into the normal path bytecode where you want but not into the catch-all path bytecode.You might assume N=4 will make your rule work but you must not forget to count reads of inStream that occur in the first bytecode section for the finally block after the condition test (e.g. the reference made in the subsequent call instream.close()). They will all appear as getfield operations in the first section and add to the count before the getfield which implements the instream != null condition test in the second section. If you count carefully (or experiment) you can work out the value of N which will make the rule work but -- like I said -- not exactly user-friendly.

                           

                          I am afraid this example doesn't really have any better alternative than that last option. You could also inject at every read of inStream (AT READ $inStream ALL) but that probably won't really give you the behaviour you want.

                           

                          There is one other option if i) the code is your own and ii) you really need to be able to inject at a point like this in order to test the code. At the start of the finally block you could add a call to a private static method which does nothing (let's assume it is called marker()) and inject AT CALL marker(). That should be safe -- i.e. make no change to the semantics of your app code when running without Byteman -- and should not hurt performance -- the JVM will optimize the call away at runtime.

                           

                          regards,

                           

                           

                          Andrew Dinn

                          • 10. Re: java.lang.NoClassDefFoundError: org/jboss/byteman/rule/exception/EarlyReturnException
                            Matthew Thurmaier Newbie

                            Thank you. Your answer makes perfect sense. I've followed through with your suggestions and been able to make more progress. Now, however, I'm stuck on a different (relate) problem. Just posted about it in a fresh thread

                            (Instrumenting classes from both boot and non-boot in Tomcat)

                             

                            If you can look at that thread and reply, I'd be very grateful. Thanks!