1 2 Previous Next 18 Replies Latest reply on Feb 29, 2012 11:50 AM by adinn

    Does rule condition support null checking?

    ant_db

      Hi,

       

      Is it possible to create rule that should does actions only if some variable is not null?

      So the rule like this:

       

      RULE rule

      CLASS Foo

      METHOD bar

      AT EXIT

      IF $! != null

      DO traceln("yes, it is possible!")

      ENDRULE

        • 1. Re: Does rule condition support null checking?
          adinn

          Hi Anton,

          Anton Ryabtsev wrote:


          Is it possible to create rule that should does actions only if some variable is not null?

          So the rule like this:

           

          RULE rule

          CLASS Foo

          METHOD bar

          AT EXIT

          IF $! != null

          DO traceln("yes, it is possible!")

          ENDRULE

           

          Yes, it is possible. In fact, the example above probably ought to work. However, you may find that in some cases when you supply null as a literal in your rule code the type checker is unable to identify a type for the literal at the point of mention and so rejects your rule with a type error.

           

          Initially this was very broken. Now it should only be rare cases where the type checker cannto handle a mention of null. There is still an outstanding JIRA for these remaining cases.

           

          Do you have a specific reason for asking? For example, have you found a case which Byteman cannot handle? If so I'll be happy to look at it and see if it is possible to fix Byteman to deal with it or else to rewrite your rule to work round this limitation.

          • 2. Re: Does rule condition support null checking?
            ant_db

            Hi Andrew,

             

            If I try to apply the above rule to the next class

             

             

            {code}

            public class Foo {

             

                public String bar(int input) {

                    if ( input == 0 ) {

                        return null;

                    }

             

                    return "bar";

                }

             

            }

            {code}

             

             

            I get this exception:

            org.jboss.byteman.rule.exception.TypeException: NullLiteral.typeCheck : unable to derive type for null from context

                at org.jboss.byteman.rule.expression.NullLiteral.typeCheck(NullLiteral.java:68)

                at org.jboss.byteman.rule.expression.ComparisonExpression.typeCheck(ComparisonExpression.java:53)

            • 3. Re: Does rule condition support null checking?
              ant_db

              I believe it is a different issue, but I can't use the above rule if my class looks like as the following:

               

               

              {code}

              public class Foo {

               

                  public void bar() {

                      synchronized ( this ) {

                          for ( int i = 0; i < 10; i++ ) {

                              System.out.println(i);

                          }

                      }

                  }

               

              }

              {code}

               

               

              In this example the exception is like this:

               

               

              java.lang.NullPointerException

                  at org.jboss.byteman.agent.adapter.cfg.CFG.computeContainment(CFG.java:1108)

                  at org.jboss.byteman.agent.adapter.cfg.CFG.carryForward(CFG.java:962)

                  at org.jboss.byteman.agent.adapter.cfg.CFG.split(CFG.java:1240)

                  at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.visitJumpInsn(RuleTriggerMethodAdapter.java:776)

                  at org.jboss.byteman.agent.adapter.EntryTriggerAdapter$EntryTriggerMethodAdapter.visitJumpInsn(EntryTriggerAdapter.java:176)

                  at org.jboss.byteman.objectweb.asm.tree.JumpInsnNode.accept(Unknown Source)

                  at org.jboss.byteman.objectweb.asm.tree.InsnList.accept(Unknown Source)

                  at org.jboss.byteman.objectweb.asm.tree.MethodNode.accept(Unknown Source)

                  at org.jboss.byteman.objectweb.asm.commons.JSRInlinerAdapter.visitEnd(Unknown Source)

                  at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                  at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                  at org.jboss.byteman.agent.Transformer.transform(Transformer.java:746)

                  at org.jboss.byteman.test.TestScript.checkRules(TestScript.java:266)

                  at org.jboss.byteman.test.TestScript.testScript(TestScript.java:139)

                  at org.jboss.byteman.test.TestScript.main(TestScript.java:98)

              • 4. Re: Does rule condition support null checking?
                adinn

                HI Anton,

                 

                Your rule does indeed fail to typecheck which is not what I expected. I thought the changes I made to partially resolve BYTEMAN-86 had dealt with this case but clearly there is more work needed. Anyway, this fairly simple variant of your rule works ok.

                 

                RULE rule

                CLASS Bar

                METHOD bar

                AT EXIT

                BIND nullStr : String = null

                IF $! != nullStr

                DO traceln("yes, it is possible!")

                ENDRULE

                 

                In this version the declaration of local variable nullStr with type String provides the type checker with an expected type for the null literal used to initialize the variable.

                • 5. Re: Does rule condition support null checking?
                  adinn

                  Anton Ryabtsev wrote:

                   

                  java.lang.NullPointerException

                      at org.jboss.byteman.agent.adapter.cfg.CFG.computeContainment(CFG.java:1108)

                      at org.jboss.byteman.agent.adapter.cfg.CFG.carryForward(CFG.java:962)

                      at org.jboss.byteman.agent.adapter.cfg.CFG.split(CFG.java:1240)

                      at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.visitJumpInsn(RuleTriggerMethodAdapter.java:776)

                      at org.jboss.byteman.agent.adapter.EntryTriggerAdapter$EntryTriggerMethodAdapter.visitJumpInsn(EntryTriggerAdapter.java:176)

                      at org.jboss.byteman.objectweb.asm.tree.JumpInsnNode.accept(Unknown Source)

                      at org.jboss.byteman.objectweb.asm.tree.InsnList.accept(Unknown Source)

                      at org.jboss.byteman.objectweb.asm.tree.MethodNode.accept(Unknown Source)

                      at org.jboss.byteman.objectweb.asm.commons.JSRInlinerAdapter.visitEnd(Unknown Source)

                      at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                      at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                      at org.jboss.byteman.agent.Transformer.transform(Transformer.java:746)

                      at org.jboss.byteman.test.TestScript.checkRules(TestScript.java:266)

                      at org.jboss.byteman.test.TestScript.testScript(TestScript.java:139)

                      at org.jboss.byteman.test.TestScript.main(TestScript.java:98)

                   

                  Ooh, that's exciting! I'll take a look at this and see if I can find out what is causing the exception. Can you confirm what version of Byteman you are using?

                  • 6. Re: Does rule condition support null checking?
                    ant_db

                    Thanks for your help, Andrew.

                     

                    Byteman version: 2.0.0

                    • 7. Re: Does rule condition support null checking?
                      adinn

                      Hi Anton,

                       

                      Anton Ryabtsev wrote:

                       

                      Thanks for your help, Andrew.

                       

                      Byteman version: 2.0.0

                       

                      That's rather strange. When I ran bmcheck on your class and rule I did not get this null pointer exception. I just got the typecheck error you posted earlier.

                       

                      I would very much like to find out what is going on here as there is obviously something wrong but I don't really know what

                       

                      Are the code and rule script which gave this exception exactly as you specified in the earlier notes?

                       

                      Can you provide the sequence of commands you ran to generate the error?

                       

                      Also, what is the OS and JVM you are using?

                       

                      Thanks for any info you can provide

                      • 8. Re: Does rule condition support null checking?
                        adinn

                        Ah,ok, I think that was my mistake. I am now getting an exception but not the one you are seeing. I get this

                         

                        [adinn@sputstik byteman]$ bmcheck -cp src foo.btm

                        checking rule rule

                        ERROR : Unexpected exception transforming class Foo using  rule "rule" loaded from foo.btm line 5

                         

                        java.lang.NullPointerException

                            at org.jboss.byteman.objectweb.asm.Frame.a(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.MethodWriter.visitVarInsn(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.MethodAdapter.visitVarInsn(Unknown Source)

                            at org.jboss.byteman.agent.adapter.RuleGeneratorAdapter.visitVarInsn(RuleGeneratorAdapter.java:1425)

                            at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.visitVarInsn(RuleTriggerMethodAdapter.java:713)

                            at org.jboss.byteman.agent.adapter.RuleGeneratorAdapter.storeLocal(RuleGeneratorAdapter.java:1493)

                            at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.doReturnOrThrowSave(RuleTriggerMethodAdapter.java:297)

                            at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.injectTriggerPoint(RuleTriggerMethodAdapter.java:1102)

                            at org.jboss.byteman.agent.adapter.ExitTriggerAdapter$ExitTriggerMethodAdapter.visitInsn(ExitTriggerAdapter.java:79)

                            at org.jboss.byteman.objectweb.asm.tree.InsnNode.accept(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.tree.InsnList.accept(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.tree.MethodNode.accept(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.commons.JSRInlinerAdapter.visitEnd(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                            at org.jboss.byteman.objectweb.asm.ClassReader.accept(Unknown Source)

                            at org.jboss.byteman.agent.Transformer.transform(Transformer.java:746)

                            at org.jboss.byteman.test.TestScript.checkRules(TestScript.java:266)

                            at org.jboss.byteman.test.TestScript.testScript(TestScript.java:139)

                            at org.jboss.byteman.test.TestScript.main(TestScript.java:98)

                         

                        TestScript: 1 total errors

                                    0 total warnings

                                    0 parse errors

                                    0 type errors

                                    0 type warnings

                         

                         

                        The error above is happening because your rule mentions variable $! but the method you are injecting into has return type void. What should happen is that the initial check to see whether the candidate method is a valid target for the rule should notice that you are using $! and realise that this is invalid. Insteda it goes on to inject the trigger code into the target method and tries to create a local var slot to save the return value on the stack. This breaks because i) there is no return value on the stack and ii) it is trying to create a local var slot with type void. So, I need to fix the trigger injecton code to inlcude this preliminary check. I will raise a JIRA for this and psot a reference on this thread  (I also probably need to do the same for AFTER CALL rules where $! refers to the return value form the called method).

                         

                        That said, I don't know why you are seeing a different exception trace. So, details of how you got there would be very welcome.

                        • 9. Re: Does rule condition support null checking?
                          ant_db

                          Well, I use next rule to produce this exciting thing(sorry for misleading you):

                           

                          RULE rule

                          CLASS Foo

                          METHOD bar

                          AT ENTRY

                          IF true

                          DO traceln("yes, it works!")

                          ENDRULE

                           

                          OS: WinXP

                          JVM: Sun jdk_1.6.0_21

                          • 10. Re: Does rule condition support null checking?
                            adinn

                            Hi Anton,

                            Anton Ryabtsev wrote:

                             

                            Well, I use next rule to produce this exciting thing(sorry for misleading you):

                             

                            RULE rule

                            CLASS Foo

                            METHOD bar

                            AT ENTRY

                            IF true

                            DO traceln("yes, it works!")

                            ENDRULE

                             

                            OS: WinXP

                            JVM: Sun jdk_1.6.0_21

                             

                            Hmm, that's interestingh. When I run this on Linux it works without any exception. I will try it on XP when I get a chance (my XP machine is at home) and let you know what happens.

                            • 11. Re: Does rule condition support null checking?
                              adinn

                              Could you help me by posting the output when you run the following command

                               

                              javap -c -verbose -private -classpath XXX Foo

                               

                              where you need to substitute the path to Foo.class in place of XXX (or omit -classpath XXX if your class file is in the working directory)

                               

                              It looks like the problem is happening during scanning of the bytecode when a jump instruction is reached so seeing the bytecode might be very useful

                              • 12. Re: Does rule condition support null checking?
                                ant_db

                                Attached

                                • 13. Re: Does rule condition support null checking?
                                  adinn

                                  Oooh, it gets even more exciting!! Can you tell me what bytecode compiler (i.e. javac program) was used to generate your class file? It looks (maybe?) like the code the Jikes compiler generates. Anyway, Byteman is going to barf on this sort of code because of the way the loop code is generated. There is nothing wrong with your file as bytecode -- it is perfectly legitimate. The problem belongs to Byteman's code analyzer (class CFG whihc you can see in the stacktrace) .

                                   

                                  If you (or anyone else reading this thread) want to understand the details then here goes. Otherwise close your eyes now.

                                   

                                  Byteman expects that the first entry to every basic block of code occurs either via a drop through or a forward jump in other words primary control flow follows bytecode order. Of course, if there is a for or while loop in a method then the bytecode will have to (re-)enter a block via a backward jump but Byteman expects the first instructions in the loop condition and loop body to be arrived at via a forward transfer of control. This assumption may be invalid for your javac compiler but it is necessary because Byteman needs to push constraints through the code as it traverses the instruction sequence.

                                   

                                  In this specific case the constraint is that there is a monitorenter before the loop body (this is the opening half of how synchronized is implemented) and it means that any path out of the loop needs to include a monitorexit (the other half of how syncrhonized is implemented) which Byteman can pair up with its corresponding monitorenter.

                                   

                                  Now, with the code generated by OpenJDK's javac the loop condition comes at the top of the loop and skips over the body if it is false. The body directly follows after the condition and there is an unconditional jump backwards at the end of the loop to retest the condition.

                                   

                                  public void bar();

                                    Code:

                                     Stack=2, Locals=4, Args_size=1

                                     0:    aload_0

                                     1:    dup

                                     2:    astore_1

                                     3:    monitorenter

                                     4:    iconst_0

                                     5:    istore_2

                                     6:    iload_2

                                     7:    bipush    10

                                     9:    if_icmpge    25

                                     12:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;

                                     15:    iload_2

                                     16:    invokevirtual    #3; //Method java/io/PrintStream.println:(I)V

                                     19:    iinc    2, 1

                                     22:    goto    6

                                     25:    aload_1

                                     26:    monitorexit

                                     27:    goto    35

                                     30:    astore_3

                                     31:    aload_1

                                     32:    monitorexit

                                     33:    aload_3

                                     34:    athrow

                                     35:    return

                                   

                                  You can see the loop condition being entered at offest 6 (iload_2 loads the loop counter which is compared against constant value 10) and the loop body entered at offset 12.

                                   

                                  Unfortunately with the bytecode you provided the loop condition is at the bottom of the loop starting at offset 19. The loop body starts at offset 9 and is skipped over at loop start by a forward jump at offset 6. The loop condition ends with a conditional jump back to the start of the loop in place of the unconditional jump we saw before.

                                   

                                  public void bar();

                                    Code:

                                     Stack=2, Locals=3, Args_size=1

                                     0:    aload_0

                                     1:    dup

                                     2:    astore_1

                                     3:    monitorenter

                                     4:    iconst_0

                                     5:    istore_2

                                     6:    goto    19

                                     9:    getstatic    #15; //Field java/lang/System.out:Ljava/io/PrintStream;

                                     12:    iload_2

                                     13:    invokevirtual    #21; //Method java/io/PrintStream.println:(I)V

                                     16:    iinc    2, 1

                                     19:    iload_2

                                     20:    bipush    10

                                     22:    if_icmplt    9

                                     25:    aload_1

                                     26:    monitorexit

                                     27:    goto    33

                                     30:    aload_1

                                     31:    monitorexit

                                     32:    athrow

                                     33:    return

                                   

                                  So, when Byteman sees the goto at instruction 6 it can propagate the monitorenter constraint to the end of the loop body but but it does not yet know that the loop body code starting at offset 9 is also reachable from the monitorenter. So, when Byteman analyzes this body code it does not know that a  monitorenter will have happened before this block is reached. So, when it gets to the monitorexit in the block starting at instruction 25 it has lost track of the corresponding monitorenter. The null pointer is supposed to be a reference to instruction 3 only there is no such reference.

                                   

                                  Ok, you can open your eyes now :-)

                                   

                                  I'll raise another JIRA for this but I cannot see it getting fixed very soon. This assumption is deep in the heart of the Byteman code generation strategy and is key to why Byteman can transform code relatively quickly. Anyway, thanks for reporting the problem and providing all the info needed to identify where things are going wrong.

                                   

                                  regards,

                                   

                                   

                                  Andrew Dinn

                                  • 14. Re: Does rule condition support null checking?
                                    ant_db

                                    I use Eclipse to generate it. So guess, it is ECJ.

                                     

                                    Thanks for quick reply.

                                    1 2 Previous Next