Unexpected behavior in TRY-CATCH-FINALLY
radek.koubsky Sep 28, 2015 6:34 AMHi,
I am using Byteman in try-catch-finally block and something does not work as I would expect.
Byteman 3.0.1
wildfly-8.2.0.Final,
resteasy version 3.0.10.Final:
source code: https://github.com/RadekKoubsky/byteman-wildfly-log/blob/master/rules/rest.btm
Here is the source code for both cases:
public void service(String httpMethod, HttpServletRequest request, HttpServletResponse response, boolean handleNotFound) throws IOException, NotFoundException { try { //logger.info(httpMethod + " " + request.getRequestURL().toString()); //logger.info("***PATH: " + request.getRequestURL()); // classloader/deployment aware RestasyProviderFactory. Used to have request specific // ResteasyProviderFactory.getInstance() ResteasyProviderFactory defaultInstance = ResteasyProviderFactory.getInstance(); if (defaultInstance instanceof ThreadLocalResteasyProviderFactory) { ThreadLocalResteasyProviderFactory.push(providerFactory); } ResteasyHttpHeaders headers = null; ResteasyUriInfo uriInfo = null; try { headers = ServletUtil.extractHttpHeaders(request); uriInfo = ServletUtil.extractUriInfo(request, servletMappingPrefix); } catch (Exception e) { response.sendError(HttpServletResponse.SC_BAD_REQUEST); // made it warn so that people can filter this. logger.warn("Failed to parse request.", e); return; } HttpResponse theResponse = responseFactory.createResteasyHttpResponse(response); HttpRequest in = requestFactory.createResteasyHttpRequest(httpMethod, request, headers, uriInfo, theResponse, response); try { ResteasyProviderFactory.pushContext(HttpServletRequest.class, request); ResteasyProviderFactory.pushContext(HttpServletResponse.class, response); ResteasyProviderFactory.pushContext(SecurityContext.class, new ServletSecurityContext(request)); if (handleNotFound) { dispatcher.invoke(in, theResponse); } else { ((SynchronousDispatcher) dispatcher).invokePropagateNotFound(in, theResponse); } } finally { ResteasyProviderFactory.clearContextData(); } } finally { ResteasyProviderFactory defaultInstance = ResteasyProviderFactory.getInstance(); if (defaultInstance instanceof ThreadLocalResteasyProviderFactory) { ThreadLocalResteasyProviderFactory.pop(); } } }
1) NullPointerException
I have following rules:
#Log extracting headers RULE logServletContainerDispatcher.service.headers CLASS org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher METHOD service(String, HttpServletRequest, HttpServletResponse, boolean) AFTER WRITE $headers 2 IF true DO log($CLASS, "DEBUG", "(Method service) Extracted HTTP headers: " + $headers.requestHeaders + "\nCookies: " + $headers.cookies) ENDRULE #Log extracting uri info RULE logServletContainerDispatcher.service.uriInfo CLASS org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher METHOD service(String, HttpServletRequest, HttpServletResponse, boolean) AFTER WRITE $uriInfo 2 IF true DO log($CLASS, "DEBUG", "(Method service) Extracted URI info (see details in logs below).") ENDRULE
When I try to compile these rules, I am getting the same NullPointerException for both of them
# File /home/koubsky/byteman-wildfly-log/rules/rest.btm line 27
RULE logServletContainerDispatcher.service.headers
CLASS org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher
METHOD service(String, HttpServletRequest, HttpServletResponse, boolean)
HELPER org.jboss.byteman.koubsky.LogHelper
AFTER WRITE $headers 2
IF true
DO log($CLASS, "DEBUG", "(Method service) Extracted HTTP headers: " + $headers.requestHeaders + "\nCookies: " + $headers.cookies)
ENDRULE
Transformed in:
loader: ModuleClassLoader for Module "org.jboss.resteasy.resteasy-jaxrs:main" from local module loader @6fb525d8 (finder: local module finder @5dc7c133 (roots: /home/koubsky/Wildfly8/wildfly-8.2.0.Final/modules,/home/koubsky/Wildfly8/wildfly-8.2.0.Final/modules/system/layers/base))
trigger class: org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher
threw java.lang.NullPointerException
java.lang.NullPointerException
at org.jboss.byteman.agent.adapter.cfg.CFG.inBytemanTrigger(CFG.java:1704)
at org.jboss.byteman.agent.adapter.RuleTriggerMethodAdapter.inBytemanTrigger(RuleTriggerMethodAdapter.java:588)
at org.jboss.byteman.agent.adapter.VariableAccessTriggerAdapter$VariableAccessTriggerMethodAdapter.visitVarInsn(VariableAccessTriggerAdapter.java:136)
at org.jboss.byteman.objectweb.asm.tree.VarInsnNode.accept(Unknown Source)
at org.jboss.byteman.agent.adapter.BMInsnList.accept(BMInsnList.java:81)
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.b(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.TransformContext.transform(TransformContext.java:150)
at org.jboss.byteman.agent.Transformer.transform(Transformer.java:746)
at org.jboss.byteman.agent.Transformer.tryTransform(Transformer.java:814)
at org.jboss.byteman.agent.Transformer.tryTransform(Transformer.java:785)
at org.jboss.byteman.agent.Transformer.transform(Transformer.java:257)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:424)
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at org.jboss.byteman.agent.Retransformer.installScript(Retransformer.java:144)
at org.jboss.byteman.agent.TransformListener.handleScripts(TransformListener.java:349)
at org.jboss.byteman.agent.TransformListener.loadScripts(TransformListener.java:272)
at org.jboss.byteman.agent.TransformListener.handleConnection(TransformListener.java:225)
at org.jboss.byteman.agent.TransformListener.run(TransformListener.java:158)
NOTE: I use AFTER WRITE location specifier in different rules in the same script and it works properly. The only difference I see is try-catch-finally block in code which does not work. Am I missing something?
2) Rule is not triggered
In the same code in the last finally block, I defined this rule:
#Log popping provider factory RULE logServletContainerDispatcher.service.pop CLASS org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher METHOD service(String, HttpServletRequest, HttpServletResponse, boolean) AT INVOKE org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory.pop() IF true DO log($CLASS, "DEBUG", "(Method service) Default instance of ResteasyProviderFactory is instance of " + "ThreadLocalResteasyProviderFactory, popping provider factory.") ENDRULE
When the code is executed (and it is, I tried to debug it), the rule is not triggered. Maybe it has something to do with the try-catch-finally again.
On the other hand, this rule (which applies at the beginning of the first try block) is triggered:
#Log pushing provider factory onto stack RULE logServletContainerDispatcher.service.push CLASS org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher METHOD service(String, HttpServletRequest, HttpServletResponse, boolean) AT INVOKE org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory.push(ResteasyProviderFactory) IF true DO log($CLASS, "DEBUG", "(Method service) Default instance of ResteasyProviderFactory is instance of " + "ThreadLocalResteasyProviderFactory, pushing provider factory onto thread local stack.") ENDRULE
Thank you for help, I can make a workaround, but it is not a solution...