Is it possible to contact the switch statement endlessly?

I am writing a code quality tool. I am looking at source and compiled classes that are looking for potential infinite loops.

I can’t think that the way of expressing the code of the sauce code can depend indefinitely. I'm wrong?

Switch statements are compiled into lookupswitchand codes tableswitch. I will need to check the compilation classes for security reasons, and modifications to the bytecode allow before the quality control program processes the compiled classes. Say, is there a possible way to loop endlessly using only these opcodes, modifying a class, or generating it using assembler?

I already took care of all the other branch instructions and instructions.

Your help will be truly appreciated.

Edit: Conclusion:

As I suspected, and according to the answers given here, the switch statement in the source code can only go forward, but any branching command in the bytecode can potentially jump backward (provided that the bytecode is modified).

+4
source share
4 answers

Saying, is there a possible way to loop endlessly using only these opcodes, modifying a class, or generating it using assembler?

To have an infinite loop, you need to somehow fall behind. If you change the byte code, this can happen when you add or change a transition to go back. If not, it cannot be a cycle, infinite or otherwise.

+1
source

, - 1.6 (50), - 1.7 (51), . ( ASM5) :

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.*;

public class LookupTest {
    public static void main(String[] args) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException {
        new ClassLoader() {
            @Override
            protected Class<?> findClass(String name)
                    throws ClassNotFoundException {
                ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
                        | ClassWriter.COMPUTE_FRAMES);
                // Create public class extending java.lang.Object
                cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER, name, null,
                        "java/lang/Object", null);
                // Create default constructor
                MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V",
                        null, null);
                mv.visitCode();
                // Call superclass constructor (this is required)
                mv.visitVarInsn(ALOAD, 0);
                mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
                        "()V", false);
                // Create branch target
                Label target = new Label();
                mv.visitLabel(target);
                // System.out.println("Hello");
                mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",
                        "Ljava/io/PrintStream;");
                mv.visitLdcInsn("Hello");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream",
                        "println", "(Ljava/lang/String;)V", false);
                // switch(0) {
                mv.visitInsn(ICONST_0);
                // default: goto target;
                // }
                mv.visitLookupSwitchInsn(target, new int[0], new Label[0]);
                mv.visitMaxs(-1, -1);
                mv.visitEnd();
                cw.visitEnd();
                byte[] bytes = cw.toByteArray();
                return defineClass(name, bytes, 0, bytes.length);
            }
        }.loadClass("LookupGotoTest").newInstance();
    }
}

, V1_6 V1_7, :

Exception in thread "main" java.lang.VerifyError: Bad instruction
Exception Details:
  Location:
    LookupGotoTest.<init>()V @13: lookupswitch
  Reason:
    Error exists in the bytecode
  Bytecode:
    0x0000000: 2ab7 0008 b200 0e12 10b6 0016 03ab 0000
    0x0000010: ffff fff7 0000 0000                    
  Stackmap Table:
    full_frame(@4,{Object[#2]},{})

    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2658)
    at java.lang.Class.getConstructor0(Class.java:3062)
    at java.lang.Class.newInstance(Class.java:403)
    at LookupTest.main(LookupTest.java:46)

, goto, 1,7 -:

Label target2 = new Label();
// switch(0) {
mv.visitInsn(ICONST_0);
// default: goto target2;
// }
mv.visitLookupSwitchInsn(target2, new int[0], new Label[0]);
mv.visitLabel(target2);
// goto target
mv.visitJumpInsn(GOTO, target);

- : Java Java 1.6 StackMapTable Type Inference, 1.7 Type Checking, , lookupswitch.

, 1.7+, ASM StackMapTable.


@Holger @apangin, , , ASM, , case mv.visitLookupSwitchInsn(target, new int[]{1}, new Label[]{target});. , : , , -.

+2

- . tableswitch lookupswitch - . , . , , int . int push, 2 .

+1

:

public static void main(String... arg) {
    loop: for(;;) switch(arg.length) {
        case 0: continue;
        default: break loop;
    }
}

Oracles javac (jdk1.8)

public static void main(java.lang.String...)
  Code:
     0: aload_0
     1: arraylength
     2: lookupswitch  { // 1
                   0: 20
             default: 23
        }
    20: goto          0
    23: goto          26
    26: return

, , , . goto , Eclipse 4.4.2, :

public static void main(java.lang.String...) t
  Code:
     0: aload_0
     1: arraylength
     2: tableswitch   { // 0 to 0
                   0: 20
             default: 23
        }
    20: goto          0
    23: return

, goto s. , goto, :

public static void main(java.lang.String...) t
  Code:
     0: aload_0
     1: arraylength
     2: tableswitch   { // 0 to 0
                   0: 0
             default: 20
        }
    20: return

, . , Java, .

Thus, having a switchbytecode statement that creates a loop does not necessarily represent logic that cannot be reproduced in the Java source code. Its just a property that depends on the implementation of the compiler when they never create such a construct, but rather redundant code. Keep in mind that the tag and while/ for, and switchare the source code artifacts, and do not require a particular form of code bytes.

0
source

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


All Articles