Uploaded image for project: 'Byteman'
  1. Byteman
  2. BYTEMAN-80

Byteman fails to inject rules attached to class X whenever subclass Y extends X gets loaded before X

    Details

    • Workaround:
      Workaround Exists
    • Workaround Description:
      Hide

      Switching off overriding rule injection by setting system property org.jboss.byteman.skip.override.rules will stop this problem manifesting at the cost of disabling the use of overriding rules.

      Ensuring that superclasses to which rules are attached are loaded before employing their subclasses will also fix this problem. However, JVMs do not guarantee to make this easy (or even possible),

      Show
      Switching off overriding rule injection by setting system property org.jboss.byteman.skip.override.rules will stop this problem manifesting at the cost of disabling the use of overriding rules. Ensuring that superclasses to which rules are attached are loaded before employing their subclasses will also fix this problem. However, JVMs do not guarantee to make this easy (or even possible),

      Description

      Following introduction of support for overriding rule injection Byteman now sometimes fails to correctly inject rules. This only happens in very specific circumstances. First, consider the following example:

      class X
      {
      . . .
      }

      class Y extends X
      {
      . . .
      }

      class Z extends Y
      {
      . . .
      }

      RULE example
      CLASS ^X
      METHOD foo
      . . .
      ENDRULE

      When class Z is loaded the instrumentation package invokes the Byteman agent passing it the bytecode for Z. The instrumentation package does not ensure that classes X or Y are already loaded before doing so. Presumably, this is because any transformer in the chain of transformers might decide to modify the superclass chain, say inserting another class between Z and Y. Of course, classes X and Y may have been loaded before class Z is loaded but this will not always be the case.

      The current agent transformer inspects the super chain for class Z by looking up the classes Y and X recursively. It scans the bytecode to find the name of the immediate super "Y" and resolves this to class Y by calling loader.loadClass("Y"). IT then calls getSuper on this class to obtain class X. This is necessary because overriding rules are attached to the root class in the hierarchy of overriding methods. Since the rule specifies CLASS ^X the agent needs to transform Z.foo() so that it triggers the rule. The agent can use the name of the immediate super "Y" to lookup overriding rules on class Y but it cannot continue on to identify further super classes (and hence overriding rules attached to them) without actually resolving"Y" to Y and then traversing the superclass chain.

      Unfortunately, this causes a problem for transforming of classes Y and X. When a class such as X or Y is loaded by a thread which is inside transformer code the classloader will not re-enter the transformer. So, if class X has not been loaded when the transfomer is passed the bytecode for Z it will get loaded while the agent is looking for overriding rules but no trigger code will be injected into X (or Y). The same is true even if the rule is changed as follows:

      RULE example
      CLASS X
      METHOD foo
      . . .
      ENDRULE

      If Z (or Y) gets loaded before X then the superclass traversal will load X but fail to inject trigger code into it.

        Gliffy Diagrams

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  adinn Andrew Dinn
                  Reporter:
                  adinn Andrew Dinn
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  0 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: