Skip to content

Probes inserted at locals that will be overridden #767

@mkroghj

Description

@mkroghj

When injecting probes into functions jacoco assumes that the arguments are not overridden as per the following JVM bytecode for class Test:

public final class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
Constant pool:
   #1 = Utf8               Test
   #2 = Class              #1             // Test
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               Test.java
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = NameAndType        #6:#7          // "<init>":()V
   #9 = Methodref          #4.#8          // java/lang/Object."<init>":()V
  #10 = Utf8               this
  #11 = Utf8               LTest;
  #12 = Utf8               foo
  #13 = Utf8               (I)I
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               java/lang/System
  #17 = Class              #16            // java/lang/System
  #18 = Utf8               out
  #19 = Utf8               Ljava/io/PrintStream;
  #20 = NameAndType        #18:#19        // out:Ljava/io/PrintStream;
  #21 = Fieldref           #17.#20        // java/lang/System.out:Ljava/io/PrintStream;
  #22 = NameAndType        #12:#13        // foo:(I)I
  #23 = Methodref          #2.#22         // Test.foo:(I)I
  #24 = Utf8               java/io/PrintStream
  #25 = Class              #24            // java/io/PrintStream
  #26 = Utf8               println
  #27 = Utf8               (I)V
  #28 = NameAndType        #26:#27        // println:(I)V
  #29 = Methodref          #25.#28        // java/io/PrintStream.println:(I)V
  #30 = Utf8               Code
  #31 = Utf8               LineNumberTable
  #32 = Utf8               LocalVariableTable
  #33 = Utf8               SourceFile
{
  static int foo(int);
    descriptor: (I)I
    flags: ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: iload_0
         1: i2l
         2: lstore_0
         3: bipush        15
         5: ireturn

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: bipush        42
         5: invokestatic  #23                 // Method foo:(I)I
         8: invokevirtual #29                 // Method java/io/PrintStream.println:(I)V
        11: return
      LineNumberTable:
        line 6: 0
        line 7: 11
}

After instrumentation, the foo function looks as follows, which is not valid (therefore, the format is a bit different from javap):

.method Test.foo(I)I
 0:   invokestatic Test.$jacocoInit()[Z
 1:   astore 1
 2:   iload 0
 3:   i2l
 4:   lstore 0
 5:   ldc 15
 6:   aload 1
 7:   ldc 1
 8:   ldc 1
 9:   bastore
10:   ireturn
.end method

Here, the probe is stored into local 1, however, local 1 is overriden by lstore 0 that takes up two locals.

Steps to reproduce

java -cp out.jar -javaagent:jacocoagent.jar=destfile=foo.txt,dumponexit=true,output=true Test

JaCoCo version: 0.8.3
Operating system: Linux
Tool integration: Command line (and gradle)

Expected behaviour

Running:
java -cp out.jar -javaagent:jacocoagent.jar=destfile=foo.txt,dumponexit=true,output=true Test
should ouput 15

Actual behaviour

java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    Test.foo(I)I @34: aload_1
  Reason:
    Type long_2nd (current frame, locals[1]) is not assignable to reference type

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions