Modifying <clinit> with ASM

Hello, I have a little problem with ASM. It creates a class with a bytecode error:

Exception in thread "main" java.lang.VerifyError: Bad instruction
Exception Details:
  Location:
    me/test/Main.<clinit>()V @0: wide
  Reason:
    Error exists in the bytecode

    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
    at java.lang.Class.privateGetMethodRecursive(Unknown Source)
    at java.lang.Class.getMethod0(Unknown Source)
    at java.lang.Class.getMethod(Unknown Source)
    at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
    at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)

When I use the following code to enter code into a method <clinit>that fills a static byte array with the variable "key" ( byte[]):

   if (key.length > 128)
        this.visitVarInsn(SIPUSH, key.length);
    else
        this.visitVarInsn(BIPUSH, key.length);
    this.visitVarInsn(NEWARRAY, 8);
    for (int i = 0; i < key.length; i++) {
        this.visitInsn(DUP);
        if (i > 127) {
            this.visitVarInsn(SIPUSH, i + 32768);
        } else if (i < 6) {
            switch (i) {
                case 0:
                    this.visitInsn(ICONST_0);
                    break;
                case 1:
                    this.visitInsn(ICONST_1);
                    break;
                case 2:
                    this.visitInsn(ICONST_2);
                    break;
                case 3:
                    this.visitInsn(ICONST_3);
                    break;
                case 4:
                    this.visitInsn(ICONST_4);
                    break;
                case 5:
                    this.visitInsn(ICONST_5);
                    break;
                default:
                    System.out.println("Logic mistake!");
                    break;
            }
        }
        else {
            this.visitVarInsn(BIPUSH, i);
        }
        if (key[i] < 6 && key[i] >= 0) {
            switch (key[i]) {
                case 0:
                    this.visitInsn(ICONST_0);
                    break;
                case 1:
                    this.visitInsn(ICONST_1);
                    break;
                case 2:
                    this.visitInsn(ICONST_2);
                    break;
                case 3:
                    this.visitInsn(ICONST_3);
                    break;
                case 4:
                    this.visitInsn(ICONST_4);
                    break;
                case 5:
                    this.visitInsn(ICONST_5);
                    break;
                default:
                    System.out.println("Logic mistake!");
                    break;
            }
        } else {
            this.visitVarInsn(BIPUSH, key[i]);
        }
        this.visitInsn(BASTORE);
0
source share
1 answer

The main reason for incorrect code is your multiple misuse visitVarInsn.

visitVarInsn , . , , , . ,

this.visitVarInsn(NEWARRAY, 8);

this.visitIntInsn(NEWARRAY, Opcodes.T_BYTE);

this.visitVarInsn(SIPUSH, key.length); this.visitVarInsn(BIPUSH, key.length);, , . ,

if (key.length > 128)
    this.visitVarInsn(SIPUSH, key.length);
else
    this.visitVarInsn(BIPUSH, key.length);

, 128. , this.visitVarInsn(SIPUSH, i + 32768); + 32768 .

, . , , , . , InstructionAdapter, MethodVisitor, iconst(int), ICONST_x, BIPUSH, SIPUSH LDC. , GeneratorAdapter , push(int) .

, GeneratorAdapter, ,

push(key.length);
newArray(Type.BYTE_TYPE);
for(int i = 0; i < key.length; i++) {
    this.visitInsn(Opcodes.DUP);
    push(i);
    push(key[i]);
    visitInsn(Opcodes.BASTORE);
}
+3

Source: https://habr.com/ru/post/1656187/


All Articles