Can byteman trigger a rule on a lambda?

241 Views Asked by At

The latest Byteman documentation (4.0.16) mentions inner classes, but doesn't mention lambdas. I have a rule looking like:

RULE showdir
CLASS ReportService
METHOD lambda$retrieveReport$0
AT ENTRY
IF TRUE
DO System.out.println("XXXXXXXX");
ENDRULE

However it never seems to trigger. When I run bmsubmit without arguments it shows the rule but does not mention a trigger method. I have checked the method name with javap, and it's correct. I can trigger on other non-lambda methods of this class. I'm running AdoptOpenJdk 8 on Alpine Linux.

Does Byteman support lambdas? Do I need to do something else to have the rule trigger?

2

There are 2 best solutions below

3
On BEST ANSWER

Update : The behavior was changed in version 4.0.17 (BYTEMAN-416), rules can now be triggered on a lambda


I was able to reproduce the issue using a simple class BytemanTest with two lambdas (source code at the end).

Short answer

Byteman ignores lambdas because they are marked as 'generated code' by the compiler in the bytecode.

Long answer:

(At least in my tests) Lambdas are flagged, by the compiler, as ACC_SYNTHETIC in the generated bytecode.

From The Java® Virtual Machine Specification :

The ACC_SYNTHETIC flag indicates that this method was generated by a compiler and does not appear in source code, unless it is one of the methods named in §4.7.8.

The following is an excerpt from the output of javap -v -p -s -c BytemanTest.class :

...
private static java.lang.String lambda$doSomething$1(java.lang.String);
    descriptor: (Ljava/lang/String;)Ljava/lang/String;
    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
...
private static void lambda$main$0(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: (0x100a) ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
        stack=3, locals=1, args_size=1

Byteman ignores methods that have the flag ACC_SYNTHETIC.

This behaviour was (probably) first introduced in this ticket BYTEMAN-58 (In commit ac4cbb4f. The flag test was in the *Adapter classes).

In Byteman's source code for v4.0.16, The test to match the target method is done in TransformContext#matchTargetMethod and it ignores methods flagged as ACC_SYNTHETIC :

if ((access & (Opcodes.ACC_NATIVE|Opcodes.ACC_ABSTRACT|Opcodes.ACC_SYNTHETIC)) != 0 ||
    !targetMethodName.equals(name) ||
    (!targetDescriptor.equals("") && !TypeHelper.equalDescriptors(targetDescriptor, desc))) {
        return false;
}

My test class

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class BytemanTest {
    public static void main(String[] args){
        BytemanTest bt = new BytemanTest();

        bt.doSomething(args).forEach((s) -> {
            System.out.println("Out : " + s);
        });

    }

    public List<String> doSomething(String[] args){
        return Arrays.stream(args).map( s -> s + "_test").collect(Collectors.toList());
    }
}

My byteman rule:

RULE showdir
CLASS BytemanTest
METHOD lambda$main$0
AT ENTRY
IF TRUE
DO System.out.println("lambda matched");
ENDRULE
8
On

Hmm, grabbing the name of the method which implements the body of the lambda out of a javap decompile is a neat trick for identifying the target method. I'm not sure why Byteman is failing to inject coe. Could you report this via the Byteman JIRA instance? I'll investigate and report the outcome on the JIRA. It may actually be possible to make this work.