wala / WALA

T.J. Watson Libraries for Analysis, with frontends for Java, Android, and JavaScript, and may common static program analyses
http://github.com/wala/WALA
Eclipse Public License 2.0
762 stars 221 forks source link

[Shrike] StackMapTable problem when instrumenting MySQL drivers #185

Open intersimone999 opened 7 years ago

intersimone999 commented 7 years ago

Hello.

I'm using Shrike to instrument bytecode. Specifically, I need to add some instructions before return statements. For example (in Java): return x; would become something like:

newvar = x;
if (Controller.instrumentationEnabled()) {
    Controller.callMethod(newvar);
}
return newvar;

where newvar in Bytecode has, as index, the maximum local variable index used in the method + 1. For example, if the method uses 5 local variables (from 0 to 4), i use 5 to indicate "newvar".

This seems to work fine in general, but I'm having troubles with the method "executeQuery(java.lang.String)" of the class com.mysql.cj.jdbc.StatementImpl of MySQL drivers for JDBC version 6.0.6. In this case, when I run the instrumented code, I get a java.lang.ClassFormatError:StackMapTable format error: reserved frame type.

Actually, if I run javap on the instrumented class, instead of printing the StackMapTable, it prints this:

Error: java.lang.reflect.InvocationTargetException
        StackMapTable: length = 0x2FA
         00 1A FE 00 54 00 03 07 05 8E 07 05 8F 07 05 8E
         00 00 FA 00 08 00 00 00 00 FF 00 44 00 0F 07 05
         84 07 05 7A 07 05 8E 07 05 8F 01 00 00 00 00 00
         00 00 00 00 07 05 8E 00 01 07 05 90 FF 00 03 00
         05 07 05 84 07 05 7A 07 05 8E 07 05 8F 01 00 00
         FF 00 41 00 0F 07 05 84 07 05 7A 07 05 8E 07 05
         [...]

All the other method, instead, have something like this:

StackMapTable: number_of_entries = 7
        frame_type = 255 /* full_frame */
          offset_delta = 31
          locals = [ class com/mysql/cj/jdbc/StatementImpl, class java/lang/Object ]
          stack = [ class java/sql/SQLException ]
        frame_type = 66 /* same_locals_1_stack_item */
          stack = [ class java/lang/Exception ]
        frame_type = 16 /* same */
        frame_type = 8 /* same */
        frame_type = 78 /* same_locals_1_stack_item */
          stack = [ class java/lang/Throwable ]
        frame_type = 252 /* append */
          offset_delta = 4
          locals = [ class com/mysql/cj/api/jdbc/result/ResultSetInternalMethods ]
        frame_type = 255 /* full_frame */
          offset_delta = 0
          locals = [ class com/mysql/cj/jdbc/StatementImpl ]
          stack = [ class com/mysql/cj/core/exceptions/CJException ]

So, in conclusion, there is some problem in the instrumentation. I think the problem is related to the introduction of the new variable. At the moment, I just use a new index, but I don't specify anywhere that this new variable is there. For some reason, Shrike is not able to correctly compute the StackMapTable in this case. It may be that I'm doing something wrong. What do you suggest? Note that I need the new variable, so removing it is not an option.

PS: You can find attached the instrumented class. StatementImpl.zip

EDIT: I confirm that the problem is related to WALA. Instead of adding the above-mentioned code, I tried to add just a call to a void method in the same locations, and the problem is still there. Here the class instrumented with the trivial call: StatementImpl.zip

msridhar commented 7 years ago

@intersimone999 any way you can provide an input class and example Shrike code such that running the code leads to a bad output?

intersimone999 commented 7 years ago

@msridhar I attach all the material you need to replicate the failure. This is the procedure I follow:

  1. I run the JUnit test case "com.ibm.wala.shrikeBT.TestStackMap.testStackMap()" and I get a "instrumented.jar" output file.

  2. I compile the example main class: javac main.java

  3. I run the main class with the instrumented jar with the command: java -cp instrumented.jar:. main

The output I get is:

Exception in thread "main" java.lang.ClassFormatError: StackMapTable format error: reserved frame type
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at main.main(main.java:3)

Instead, the expected output is: Hello world Which is the output I get if I run java -cp mysql-connector-java-6.0.6.jar:. main

failure.zip