Bytecode not refreshed on runtime rule injection | java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
garimakemwal Aug 20, 2018 4:55 AMI am trying to inject some code in Java classes ThreadPoolExecutor and Thread classes through a Helper class (attaching the Byteman Rules script).
As soon as the rules are loaded, the application starts to throw exceptions as follows, but behaves normally when the rules are unloaded.
Exception in thread "http-nio-8080-exec-2" Rule.execute called for runnable run_19java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetPublicMethods(Class.java:2902)
at java.lang.Class.getMethods(Class.java:1615)
at org.jboss.byteman.rule.expression.MethodExpression.findMethod(MethodExpression.java:266)
at org.jboss.byteman.rule.expression.MethodExpression.typeCheck(MethodExpression.java:187)
at org.jboss.byteman.rule.Action.typeCheck(Action.java:106)
at org.jboss.byteman.rule.Rule.typeCheck(Rule.java:590)
at org.jboss.byteman.rule.Rule.ensureTypeCheckedCompiled(Rule.java:521)
at org.jboss.byteman.rule.Rule.execute(Rule.java:796)
at org.jboss.byteman.rule.Rule.execute(Rule.java:777)
at java.util.concurrent.ThreadPoolExecutor.beforeExecute(ThreadPoolExecutor.java)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
NOTE : This behaviour is intermittent, and works after repeated loading/unloading (Somewhat similar to this). The same set of rules work if I supply them while starting the application and not using any Custom Helper Class.
This is a spring boot application being started with following config :
java -Dorg.jboss.byteman.transform.all -javaagent:${BYTEMAN_HOME}/lib/byteman.jar=listener:true,boot:${BYTEMAN_HOME}/lib/byteman.jar -jar sample-byteman-logger-0.1.0.jar
Since the Helper class needs to inject code in packages java.util.concurrent and java.lang, I add the same in bootstrap classpath and then load the rules as follows with bmsubmit :
bmsubmit -b application-tracer-0.0.1-SNAPSHOT.jar [JAR containing helper class]
bmsubmit -l apprules.btm
The flag org.jboss.byteman.verbose gives me following debug logs, wasn't able to spot any errors while injection :
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class org.apache.tomcat.util.net.NioBlockingSelector$BlockPoller
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class org.LatencyUtils.SimplePauseDetector$SimplePauseDetectorThread
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.LatencyUtils.SimplePauseDetector$SimplePauseDetectorThread.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class org.LatencyUtils.SimplePauseDetector$SimplePauseDetectorThread
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class org.LatencyUtils.PauseDetector$PauseDetectorThread
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.LatencyUtils.PauseDetector$PauseDetectorThread.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class org.LatencyUtils.PauseDetector$PauseDetectorThread
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class org.springframework.boot.web.embedded.tomcat.TomcatWebServer$1
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.springframework.boot.web.embedded.tomcat.TomcatWebServer$1.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class org.springframework.boot.web.embedded.tomcat.TomcatWebServer$1
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class org.springframework.context.support.AbstractApplicationContext$1
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into org.springframework.context.support.AbstractApplicationContext$1.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class org.springframework.context.support.AbstractApplicationContext$1
org.jboss.byteman.agent.Transformer : possible trigger for rule before ThreadPoolExecutor in class java.util.concurrent.ThreadPoolExecutor
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into java.util.concurrent.ThreadPoolExecutor.beforeExecute(java.lang.Thread,java.lang.Runnable) void for rule before ThreadPoolExecutor
org.jboss.byteman.agent.Transformer : inserted trigger for before ThreadPoolExecutor in class java.util.concurrent.ThreadPoolExecutor
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class java.util.logging.LogManager$Cleaner
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into java.util.logging.LogManager$Cleaner.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class java.util.logging.LogManager$Cleaner
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class java.lang.ref.Finalizer$FinalizerThread
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into java.lang.ref.Finalizer$FinalizerThread.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class java.lang.ref.Finalizer$FinalizerThread
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class java.lang.ref.Reference$ReferenceHandler
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into java.lang.ref.Reference$ReferenceHandler.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class java.lang.ref.Reference$ReferenceHandler
org.jboss.byteman.agent.Transformer : possible trigger for rule runnable run in class java.lang.Thread
RuleTriggerMethodAdapter.injectTriggerPoint : inserting trigger into java.lang.Thread.run() void for rule runnable run
org.jboss.byteman.agent.Transformer : inserted trigger for runnable run in class java.lang.Thread
Helper class :
public class LogHelper { private static final Logger LOGGER = LoggerFactory.getLogger(LogHelper.class); public void executorDecorator() { LOGGER.info("Executor helper "); } }
2 issues:
1. Do I need to restart the application to be able to see the bytecode changes, and why can't the application suddenly find 'javax/servlet/http/HttpServletRequest' in presence of simple rules. I don't see any errors for this also.
2. Is there a way to supply multiple JARs in boot: option of javagent so that I can inject the rules while starting the application (No such exceptions are seen with that) and add both byteman.jar and application-tracer in bootstrap classpath simultaneously?
Something like : boot:[${BYTEMAN_HOME}/lib/byteman.jar,application-tracer-0.0.1-SNAPSHOT.jar]
Config used :
- Byteman version : 4.0.4
- java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode)
Please let me know if I'm missing something here.
Thanks!
-
apprules.btm.zip 614 bytes