javalambdabyteman

Can byteman trigger a rule on a lambda?


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?


Solution

  • 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