From 14b4dd94f8511ece671659a0cee064bc49a2e3bf Mon Sep 17 00:00:00 2001 From: hoenicke Date: Tue, 14 Aug 2001 12:08:37 +0000 Subject: [PATCH] Added test cases. git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1347 379699f6-c40d-0410-875b-85095c16579e --- .../jode/bytecode/BasicBlockWriterTest.java | 214 +++++++++++ .../net/sf/jode/bytecode/BasicBlocksTest.java | 47 +++ .../src/net/sf/jode/bytecode/BlockTest.java | 44 +++ jode/test/src/net/sf/jode/flow/TrExcTest.java | 358 ++++++++++++++++++ .../jode/obfuscator/modules/ConstAnaTest.java | 186 +++++++++ 5 files changed, 849 insertions(+) create mode 100644 jode/test/src/net/sf/jode/bytecode/BasicBlockWriterTest.java create mode 100644 jode/test/src/net/sf/jode/bytecode/BasicBlocksTest.java create mode 100644 jode/test/src/net/sf/jode/bytecode/BlockTest.java create mode 100644 jode/test/src/net/sf/jode/flow/TrExcTest.java create mode 100644 jode/test/src/net/sf/jode/obfuscator/modules/ConstAnaTest.java diff --git a/jode/test/src/net/sf/jode/bytecode/BasicBlockWriterTest.java b/jode/test/src/net/sf/jode/bytecode/BasicBlockWriterTest.java new file mode 100644 index 0000000..508ac6a --- /dev/null +++ b/jode/test/src/net/sf/jode/bytecode/BasicBlockWriterTest.java @@ -0,0 +1,214 @@ +package net.sf.jode.bytecode; +import junit.framework.*; +import java.io.*; + +public class BasicBlockWriterTest extends TestCase implements Opcodes { + public BasicBlockWriterTest(String name) { + super(name); + } + + GrowableConstantPool gcp = new GrowableConstantPool(); + Instruction[] someNops; + Instruction[] manyNops; + Instruction[] whileHead; + Instruction[] whileCond; + Instruction[] whileFoot; + + /** + * The whileHead block in bytecode + */ + private final static String whileHeadStr="\3="; + /** + * The whileCond block in bytecode, without the if_icmpeq instruction. + */ + private final static String whileCondStr="\34\33"; + /** + * The whileFoot block in bytecode. + */ + private final static String whileFootStr="\204\2\1"; + /** + * The someNops block in bytecode, without the if_icmpeq instruction. + */ + private final static String someNopsStr="\0\0"; + + public void setUp() { + Instruction nop = Instruction.forOpcode(opc_nop); + someNops = new Instruction[] { nop, nop }; + manyNops = new Instruction[35000]; + for (int i = 0; i < manyNops.length; i++) + manyNops[i] = nop; + + whileHead = new Instruction[] { + Instruction.forOpcode(opc_ldc, new Integer(0)), + Instruction.forOpcode(opc_istore, LocalVariableInfo.getInfo(2)), + }; + whileCond = new Instruction[] { + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_if_icmpeq) + }; + whileFoot = new Instruction[] { + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(2), 1), + }; + } + + public byte[] write(BasicBlockWriter bbw) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + bbw.write(gcp, dos); + dos.close(); + return baos.toByteArray(); + } + + public void testEmpty() throws IOException { + BasicBlocks bb = new BasicBlocks(new MethodInfo("foo", "()V", 0)); + bb.setBlocks(new Block[0], null, new Handler[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + + assertEquals("Code differs", + "\0\0\0\1\0\0\0\1" /* no stack, one local, length 1 */ + +"\261" /* opc_return */ + +"\0\0" /* no exception handlers */, + new String(write(bbw))); + } + + public void testSimple() throws IOException { + Block bb1 = new Block(); + Block bb2 = new Block(); + bb1.setCode(someNops, new Block[] {bb2}); + bb2.setCode(someNops, new Block[] {null}); + BasicBlocks bb = new BasicBlocks(new MethodInfo("foo", "()V", 0)); + bb.setBlocks(new Block[] { bb1, bb2}, bb1, new Handler[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + + assertEquals("Code differs", + "\0\0\0\1\0\0\0\5" /* no stack, one local, length 5 */ + +someNopsStr+someNopsStr+"\261" + +"\0\0" /* no exception handlers */, + new String(write(bbw))); + } + + public void testWhile() throws IOException { + Block b1 = new Block(); + Block b2 = new Block(); + Block b3 = new Block(); + Block b4 = new Block(); + b1.setCode(whileHead, new Block[] { b2 }); + b2.setCode(whileCond, new Block[] { null, b3 }); + b3.setCode(someNops, new Block[] { b4 }); + b4.setCode(whileFoot, new Block[] { b2 }); + BasicBlocks bb = new BasicBlocks(new MethodInfo("a", "(I)V", 0)); + bb.setBlocks(new Block[] { b1, b2, b3, b4}, b1, new Handler[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + assertEquals(5, bbw.blockAddr.length); + assertEquals(0, bbw.blockAddr[0]); + assertEquals(2, bbw.blockAddr[1]); + assertEquals(7, bbw.blockAddr[2]); + assertEquals(9, bbw.blockAddr[3]); + assertEquals(16, bbw.blockAddr[4]); + + assertEquals("Code differs", + "\0\2\0\3\0\0\0\20" + +whileHeadStr+whileCondStr+"\237\0\13" + +someNopsStr+whileFootStr+"\247\377\366"+"\261"+"\0\0", + new String(write(bbw))); + } + + public void testTableSwitch() throws IOException { + Block b1 = new Block(); + Block b2 = new Block(); + Instruction[] switchBlock = new Instruction[] { + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_lookupswitch, new int[] { 1, 3, 5}) + }; + b1.setCode(switchBlock, new Block[] { b2, null, b1, null }); + b2.setCode(someNops, new Block[] { null }); + BasicBlocks bb = new BasicBlocks(new MethodInfo("s", "(I)V", 0)); + bb.setBlocks(new Block[] { b1, b2 }, b1, new Handler[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + assertEquals(3, bbw.blockAddr.length); + assertEquals(0, bbw.blockAddr[0]); + assertEquals(36, bbw.blockAddr[1]); + assertEquals(39, bbw.blockAddr[2]); + assertEquals("Code differs", + "\0\1\0\2\0\0\0\47" + +"\33\252\0\0" /*iload_0 + tableswitch + align */ + +"\0\0\0\45\0\0\0\1\0\0\0\5" /* def, low, high */ + +"\0\0\0\43\0\0\0\45\0\0\0\45\0\0\0\45\377\377\377\377" + +someNopsStr+"\261"+"\0\0", + new String(write(bbw))); + } + + public void testLookupSwitch() throws IOException { + Block b1 = new Block(); + Block b2 = new Block(); + Instruction[] switchBlock = new Instruction[] { + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_lookupswitch, new int[] { 1, 5, 7}) + }; + b1.setCode(switchBlock, new Block[] { b2, null, b1, null }); + b2.setCode(someNops, new Block[] { null }); + BasicBlocks bb = new BasicBlocks(new MethodInfo("s", "(I)V", 0)); + bb.setBlocks(new Block[] { b1, b2 }, b1, new Handler[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + assertEquals(3, bbw.blockAddr.length); + assertEquals(0, bbw.blockAddr[0]); + assertEquals(36, bbw.blockAddr[1]); + assertEquals(39, bbw.blockAddr[2]); + assertEquals("Code differs", + "\0\1\0\2\0\0\0\47" + +"\33\253\0\0" /*iload_0 + lookupswitch + align */ + +"\0\0\0\45\0\0\0\3" /* def , nitem */ + +"\0\0\0\1\0\0\0\43" + +"\0\0\0\5\0\0\0\45" + +"\0\0\0\7\377\377\377\377" + +someNopsStr+"\261"+"\0\0", + new String(write(bbw))); + } + + public void testException() throws IOException { + Block b1 = new Block(); + Block b2 = new Block(); + Instruction[] catchInstrs = new Instruction[] { + Instruction.forOpcode(opc_athrow) + }; + b1.setCode(someNops, new Block[] { null }); + b2.setCode(catchInstrs, new Block[0]); + BasicBlocks bb = new BasicBlocks(new MethodInfo("e", "()V", 0)); + Handler h = new Handler(b1, b1, b2, "java.lang.RuntimeException"); + bb.setBlocks(new Block[] { b1, b2 }, b1, new Handler[] {h}); + assertEquals(0, b1.blockNr); + assertEquals(1, b2.blockNr); + assertEquals(1, b1.catchers.length); + assertEquals(0, b2.catchers.length); + assertSame(h, b1.catchers[0]); + BasicBlockWriter bbw = new BasicBlockWriter(bb, gcp); + gcp.write(new DataOutputStream(new ByteArrayOutputStream())); + int cpoolEntry = gcp.putClassName("java.lang.RuntimeException"); + assertEquals(3, bbw.blockAddr.length); + assertEquals(0, bbw.blockAddr[0]); + assertEquals(3, bbw.blockAddr[1]); + assertEquals(4, bbw.blockAddr[2]); + assertEquals("Code differs", + "\0\1\0\1\0\0\0\4" + + someNopsStr + "\261" + "\277" + + "\0\1\0\0\0\3\0\3\0"+(char)cpoolEntry, + new String(write(bbw))); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new BasicBlockWriterTest("testEmpty")); + suite.addTest(new BasicBlockWriterTest("testSimple")); + suite.addTest(new BasicBlockWriterTest("testWhile")); + suite.addTest(new BasicBlockWriterTest("testTableSwitch")); + suite.addTest(new BasicBlockWriterTest("testLookupSwitch")); + suite.addTest(new BasicBlockWriterTest("testException")); + return suite; + } +} diff --git a/jode/test/src/net/sf/jode/bytecode/BasicBlocksTest.java b/jode/test/src/net/sf/jode/bytecode/BasicBlocksTest.java new file mode 100644 index 0000000..f39f174 --- /dev/null +++ b/jode/test/src/net/sf/jode/bytecode/BasicBlocksTest.java @@ -0,0 +1,47 @@ +package net.sf.jode.bytecode; +import junit.framework.*; +import java.io.*; + +public class BasicBlocksTest extends TestCase implements Opcodes { + public BasicBlocksTest(String name) { + super(name); + } + + public void testJsr() { + Block b0 = new Block(); + Block b1 = new Block(); + Block b2 = new Block(); + b0.setCode(new Instruction[] { + Instruction.forOpcode(opc_jsr) + }, new Block[] { b1, null }); + b1.setCode(new Instruction[] { + Instruction.forOpcode(opc_astore, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(1), -1), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ifeq) + }, new Block[] { b2, b0 }); + b2.setCode(new Instruction[] { + Instruction.forOpcode(opc_ret, LocalVariableInfo.getInfo(0)), + }, new Block[0]); + assertEquals("pop0", 0, b0.maxpop); + assertEquals("push0", 0, b0.maxpush); + assertEquals("delta0", 0, b0.delta); + assertEquals("pop1", 1, b1.maxpop); + assertEquals("push1", 0, b1.maxpush); + assertEquals("delta1", -1, b1.delta); + assertEquals("pop2", 0, b2.maxpop); + assertEquals("push2", 0, b2.maxpush); + assertEquals("delta2", 0, b2.delta); + BasicBlocks bb = new BasicBlocks(new MethodInfo("foo", "(I)V", 0)); + bb.setBlocks(new Block[] { b0, b1, b2 }, b0, new Handler[0]); + assertEquals("stack0", 0, b0.stackHeight); + assertEquals("stack1", 1, b1.stackHeight); + assertEquals("stack2", 0, b2.stackHeight); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new BasicBlocksTest("testJsr")); + return suite; + } +} diff --git a/jode/test/src/net/sf/jode/bytecode/BlockTest.java b/jode/test/src/net/sf/jode/bytecode/BlockTest.java new file mode 100644 index 0000000..f378b1a --- /dev/null +++ b/jode/test/src/net/sf/jode/bytecode/BlockTest.java @@ -0,0 +1,44 @@ +package net.sf.jode.bytecode; +import junit.framework.*; +import java.io.*; + +public class BlockTest extends TestCase implements Opcodes { + public BlockTest(String name) { + super(name); + } + + public void testJsr() { + Block b1 = new Block(); + Block b2 = new Block(); + Instruction jsr = Instruction.forOpcode(opc_jsr); + b1.setCode(new Instruction[] { jsr }, new Block[] { b2, null } ); + assertEquals("pop", 0, b1.maxpop); + assertEquals("push", 0, b1.maxpush); + assertEquals("delta", 0, b1.delta); + try { + b1.setCode(new Instruction[] { jsr }, new Block[] { b2 }); + fail("jsr must have two successors"); + } catch (IllegalArgumentException ex) { + } + try { + b1.setCode(new Instruction[] { jsr }, + new Block[] { null, b2 }); + fail("jsr succ mustn't be null"); + } catch (IllegalArgumentException ex) { + } + try { + b1.setCode(new Instruction[] { jsr, + Instruction.forOpcode(opc_nop) }, + new Block[] { null, b2 }); + fail("jsr must be last in block"); + } catch (IllegalArgumentException ex) { + } + + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new BlockTest("testJsr")); + return suite; + } +} diff --git a/jode/test/src/net/sf/jode/flow/TrExcTest.java b/jode/test/src/net/sf/jode/flow/TrExcTest.java new file mode 100644 index 0000000..f34f5ee --- /dev/null +++ b/jode/test/src/net/sf/jode/flow/TrExcTest.java @@ -0,0 +1,358 @@ +package net.sf.jode.flow; +import net.sf.jode.decompiler.LocalInfo; +import junit.framework.*; +import net.sf.jode.expr.*; +import net.sf.jode.type.Type; +import net.sf.jode.decompiler.TabbedPrintWriter; +import net.sf.jode.GlobalOptions; + +public class TrExcTest extends TestCase { + private static final boolean VERBOSE = false; + + public TrExcTest(String name) { + super (name); + } + + public void setUp() { + GlobalOptions.debuggingFlags |= GlobalOptions.DEBUG_CHECK; + if (VERBOSE) + GlobalOptions.debuggingFlags + |= GlobalOptions.DEBUG_ANALYZE | GlobalOptions.DEBUG_FLOW; + } + + FlowBlock[] createFlowBlocks(int n) { + FlowBlock[] flows = new FlowBlock[n]; + for (int i = 0; i < n; i++) + flows[i] = new FlowBlock(null, i, i > 0 ? flows[i-1] : null); + return flows; + } + + public void testSynchronized11() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(5); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Monitorenter */ + flows[0].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[0].appendBlock + (new InstructionBlock(new MonitorEnterOperator())); + flows[0].setSuccessors(new FlowBlock[] { flows[1] }); + + /* Synchronized Blocks */ + flows[1].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[1].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmpLocal))), tmpLocal); + flows[1].appendBlock(new JsrBlock()); + flows[1].setSuccessors(new FlowBlock[] { flows[4], flows[2] }); + + flows[2].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, tmpLocal)), tmpLocal); + flows[2].appendBlock + (new ReturnBlock(new NopOperator(Type.tUObject))); + flows[2].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + /* Catch Exception Blocks */ + flows[3].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[3].appendBlock + (new InstructionBlock(new MonitorExitOperator())); + flows[3].appendBlock + (new ThrowBlock(new NopOperator(Type.tUObject))); + flows[3].setSuccessors(new FlowBlock[0]); + + /* monitorexit subroutine */ + flows[4].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmp2Local))), tmp2Local); + flows[4].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[4].appendBlock + (new InstructionBlock(new MonitorExitOperator())); + flows[4].appendReadBlock + (new RetBlock(tmp2Local), tmp2Local); + flows[4].setSuccessors(new FlowBlock[0]); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[1],flows[2],flows[3], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue(flows[0].getBlock() instanceof SynchronizedBlock); + assertTrue(flows[0].getBlock().getSubBlocks()[0] + instanceof ReturnBlock); + } + + public void testSynchronized13() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(5); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Monitorenter */ + flows[0].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[0].appendBlock + (new InstructionBlock(new MonitorEnterOperator())); + flows[0].setSuccessors(new FlowBlock[] { flows[1] }); + + /* Synchronized Blocks */ + flows[1].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[1].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmpLocal))), tmpLocal); + flows[1].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[1].appendBlock + (new InstructionBlock(new MonitorExitOperator())); + flows[1].setSuccessors(new FlowBlock[] { flows[2] }); + + flows[2].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, tmpLocal)), tmpLocal); + flows[2].appendBlock + (new ReturnBlock(new NopOperator(Type.tUObject))); + flows[2].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + /* Catch Exception Blocks */ + flows[3].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[3].appendBlock + (new InstructionBlock(new MonitorExitOperator())); + flows[3].appendBlock + (new ThrowBlock(new NopOperator(Type.tUObject))); + flows[3].setSuccessors(new FlowBlock[0]); + + /* monitorexit subroutine */ + flows[4].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmp2Local))), tmp2Local); + flows[4].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[4].appendBlock + (new InstructionBlock(new MonitorExitOperator())); + flows[4].appendReadBlock + (new RetBlock(tmp2Local), tmp2Local); + flows[4].setSuccessors(new FlowBlock[0]); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[1],flows[2],flows[3], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue(flows[0].getBlock() instanceof SynchronizedBlock); + assertTrue(flows[0].getBlock().getSubBlocks()[0] + instanceof ReturnBlock); + } + + public void testSpecialFin() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(3); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Try Blocks */ + flows[0].setSuccessors(new FlowBlock[] { flows[2] }); + + /* Catch Exception Blocks */ + flows[1].appendBlock(new SpecialBlock(SpecialBlock.POP, 1, 0)); + flows[1].setSuccessors(new FlowBlock[] { flows[2] }); + + /* subroutine */ + flows[2].appendBlock(new DescriptionBlock("/*FINALLY*/")); + flows[2].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[0],flows[0],flows[1], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue("Try", flows[0].getBlock() instanceof TryBlock); + assertTrue("Empty", flows[0].getBlock().getSubBlocks()[0] instanceof EmptyBlock); + assertTrue("Finally", flows[0].getBlock().getSubBlocks()[1] instanceof FinallyBlock); + assertTrue("Descr", flows[0].getBlock().getSubBlocks()[1].getSubBlocks()[0] instanceof DescriptionBlock); + } + + public void testSpecialFinTryLoops() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(3); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Try Blocks */ + flows[0].setSuccessors(new FlowBlock[] { flows[0] }); + + /* Catch Exception Blocks */ + flows[1].appendBlock(new SpecialBlock(SpecialBlock.POP, 1, 0)); + flows[1].setSuccessors(new FlowBlock[] { flows[2] }); + + /* subroutine */ + flows[2].appendBlock(new DescriptionBlock("/*FINALLY*/")); + flows[2].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[0],flows[0],flows[1], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue("Try", flows[0].getBlock() instanceof TryBlock); + assertTrue("Loop", flows[0].getBlock().getSubBlocks()[0] instanceof LoopBlock); + assertTrue("Empty", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0] instanceof EmptyBlock); + assertTrue("Finally", flows[0].getBlock().getSubBlocks()[1] instanceof FinallyBlock); + assertTrue("Descr", flows[0].getBlock().getSubBlocks()[1].getSubBlocks()[0] instanceof DescriptionBlock); + } + + public void testFinBreaksJikes() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(5); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Try Blocks */ + flows[0].appendBlock(new JsrBlock()); + flows[0].setSuccessors(new FlowBlock[] { flows[3], flows[4] }); + + /* Catch Exception Blocks */ + flows[1].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmpLocal))), tmpLocal); + flows[1].appendBlock(new JsrBlock()); + flows[1].setSuccessors(new FlowBlock[] { flows[3], flows[2] }); + + flows[2].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, tmpLocal)), tmpLocal); + flows[2].appendBlock + (new ThrowBlock(new NopOperator(Type.tUObject))); + flows[2].setSuccessors(new FlowBlock[0]); + + /* subroutine */ + flows[3].appendBlock(new SpecialBlock(SpecialBlock.POP, 1, 0)); + flows[3].setSuccessors(new FlowBlock[] { flows[4] }); + + flows[4].appendBlock(new DescriptionBlock("/*HERE*/")); + flows[4].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[0],flows[0],flows[1], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue("Sequ", flows[0].getBlock() instanceof SequentialBlock); + assertTrue("Loop", flows[0].getBlock().getSubBlocks()[0] instanceof LoopBlock); + assertTrue("Try", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0] instanceof TryBlock); + assertTrue("Empty", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[0] instanceof EmptyBlock); + assertTrue("Finally", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[1] instanceof FinallyBlock); + assertTrue("Break", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[1].getSubBlocks()[0] instanceof BreakBlock); + assertTrue("Descr", flows[0].getBlock().getSubBlocks()[1] + instanceof DescriptionBlock); + } + + public void testFinCondBreaks() throws java.io.IOException { + FlowBlock[] flows = createFlowBlocks(6); + LocalInfo thisLocal = new LocalInfo(null, 0); + LocalInfo tmpLocal = new LocalInfo(null, 1); + LocalInfo tmp2Local = new LocalInfo(null, 2); + + /* Try Blocks */ + flows[0].appendBlock(new JsrBlock()); + flows[0].setSuccessors(new FlowBlock[] { flows[3], flows[5] }); + + /* Catch Exception Blocks */ + flows[1].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmpLocal))), tmpLocal); + flows[1].appendBlock(new JsrBlock()); + flows[1].setSuccessors(new FlowBlock[] { flows[3], flows[2] }); + + flows[2].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, tmpLocal)), tmpLocal); + flows[2].appendBlock + (new ThrowBlock(new NopOperator(Type.tUObject))); + flows[2].setSuccessors(new FlowBlock[0]); + + /* subroutine */ + flows[3].appendWriteBlock + (new InstructionBlock + (new StoreInstruction + (new LocalStoreOperator(Type.tUObject, tmp2Local))), tmp2Local); + flows[3].appendReadBlock + (new InstructionBlock + (new LocalLoadOperator(Type.tUObject, null, thisLocal)), thisLocal); + flows[3].appendBlock(new ConditionalBlock + (new CompareUnaryOperator + (Type.tUObject, Operator.EQUALS_OP))); + flows[3].setSuccessors(new FlowBlock[] { flows[4], flows[5] }); + flows[4].appendReadBlock + (new RetBlock(tmp2Local), tmp2Local); + flows[4].setSuccessors(new FlowBlock[0]); + + flows[5].appendBlock(new DescriptionBlock("/*HERE*/")); + flows[5].setSuccessors(new FlowBlock[] { FlowBlock.END_OF_METHOD }); + + flows[0].addStartPred(); + TransformExceptionHandlers exc = new TransformExceptionHandlers(flows); + exc.addHandler(flows[0],flows[0],flows[1], null); + exc.analyze(); + flows[0].analyze(); + flows[0].removeStartPred(); + if (VERBOSE) + flows[0].dumpSource(new TabbedPrintWriter(GlobalOptions.err)); + assertTrue("Sequ", flows[0].getBlock() instanceof SequentialBlock); + assertTrue("Loop", flows[0].getBlock().getSubBlocks()[0] instanceof LoopBlock); + assertTrue("Try", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0] instanceof TryBlock); + assertTrue("Empty", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[0] instanceof EmptyBlock); + assertTrue("Finally", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[1] instanceof FinallyBlock); + assertTrue("If", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[1].getSubBlocks()[0] instanceof IfThenElseBlock); + assertTrue("Break", flows[0].getBlock().getSubBlocks()[0].getSubBlocks()[0].getSubBlocks()[1].getSubBlocks()[0].getSubBlocks()[0] instanceof BreakBlock); + assertTrue("Descr", flows[0].getBlock().getSubBlocks()[1] + instanceof DescriptionBlock); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new TrExcTest("testSynchronized11")); + suite.addTest(new TrExcTest("testSynchronized13")); + suite.addTest(new TrExcTest("testSpecialFin")); + suite.addTest(new TrExcTest("testSpecialFinTryLoops")); + suite.addTest(new TrExcTest("testFinBreaksJikes")); + suite.addTest(new TrExcTest("testFinCondBreaks")); + return suite; + } +} diff --git a/jode/test/src/net/sf/jode/obfuscator/modules/ConstAnaTest.java b/jode/test/src/net/sf/jode/obfuscator/modules/ConstAnaTest.java new file mode 100644 index 0000000..a9ec5bb --- /dev/null +++ b/jode/test/src/net/sf/jode/obfuscator/modules/ConstAnaTest.java @@ -0,0 +1,186 @@ +package net.sf.jode.obfuscator.modules; +import net.sf.jode.bytecode.*; +import net.sf.jode.GlobalOptions; +import junit.framework.*; +import java.util.BitSet; +import java.io.PrintWriter; + +public class ConstAnaTest extends TestCase implements Opcodes { + ConstantAnalyzer ca; + Instruction[] callJsrInstr; + BasicBlocks jsrMethod; + + public ConstAnaTest(String name) { + super(name); + } + + public void setUp() { + ca = new ConstantAnalyzer(); + createJsrMethod(); + } + + public void createJsrMethod() { + callJsrInstr = new Instruction[] { + Instruction.forOpcode(opc_jsr) + }; + + Block b0 = new Block(); + Block b1 = new Block(); + Block b2 = new Block(); + b0.setCode(callJsrInstr, new Block[] { b1, null }); + b1.setCode(new Instruction[] { + Instruction.forOpcode(opc_astore, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(1), -1), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ifeq) + }, new Block[] { b2, b0 }); + b2.setCode(new Instruction[] { + Instruction.forOpcode(opc_ret, LocalVariableInfo.getInfo(2)), + }, new Block[0]); + jsrMethod = new BasicBlocks(new MethodInfo("foo", "(I)V", 0)); + jsrMethod.setBlocks(new Block[] { b0, b1, b2 }, + b0, new Handler[0]); + } + + public void testSimple() throws Exception { + Block b0 = new Block(); + Block b1 = new Block(); + Block b2 = new Block(); + b0.setCode(new Instruction[] { + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(1), 1), + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(2), 1), + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(3), 1), + }, new Block[] { b1 }); + b1.setCode(new Instruction[] { + Instruction.forOpcode(opc_ldc, new Integer(0)), + Instruction.forOpcode(opc_istore, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ldc, new Integer(4)), + Instruction.forOpcode(opc_istore, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_ldc, new Integer(0)), + Instruction.forOpcode(opc_istore, LocalVariableInfo.getInfo(3)), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ifeq) + }, new Block[] { b2, b0 }); + b2.setCode(new Instruction[] { + Instruction.forOpcode(opc_iinc, LocalVariableInfo.getInfo(1), 1), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_if_icmplt) + }, new Block[] { b2, null }); + BasicBlocks bb = new BasicBlocks(new MethodInfo("foo", "()V", 0)); + bb.setBlocks(new Block[] { b0, b1, b2 }, b1, new Handler[0]); + + ca.analyzeCode(null, bb); + + BitSet reachable = (BitSet) ca.bbInfos.get(bb); + assertEquals("Reachable set", + "{1, 2}", reachable.toString()); + assertEquals("constant flow", + ca.CONSTANTFLOW, + Class.forName("net.sf.jode.obfuscator.modules.ConstantAnalyzer$ConstantInfo") + .getDeclaredField("flags") + .getInt(ca.constantInfos.get(b1.getInstructions()[7]))); + ca.transformCode(bb); + + Block[] blocks = bb.getBlocks(); + assertEquals(2, blocks.length); + assertEquals(1, blocks[0].getSuccs().length); + assertEquals(blocks[1], blocks[0].getSuccs()[0]); + assertEquals(2, blocks[1].getSuccs().length); + assertEquals(blocks[1], blocks[1].getSuccs()[0]); + assertEquals(null, blocks[1].getSuccs()[1]); + } + + public void testJsr() throws Exception { + Block[] blocks = jsrMethod.getBlocks(); + + ca.analyzeCode(null, jsrMethod); + + BitSet reachable = (BitSet) ca.bbInfos.get(jsrMethod); + assertEquals("Reachable set", + "{0, 1, 2}", reachable.toString()); + ca.transformCode(jsrMethod); + + blocks = jsrMethod.getBlocks(); + assertEquals(3, blocks.length); + assertEquals(2, blocks[0].getSuccs().length); + assertEquals(blocks[1], blocks[0].getSuccs()[0]); + assertEquals(null, blocks[0].getSuccs()[1]); + assertEquals(2, blocks[1].getSuccs().length); + assertEquals(0, blocks[2].getSuccs().length); + } + + public void testNestedJsr() throws Exception { + Block b0 = new Block(); + Block b1 = new Block(); + Block b2 = new Block(); + Block b3 = new Block(); + Block b4 = new Block(); + Block b5 = new Block(); + Block b6 = new Block(); + Block b7 = new Block(); + Block b8 = new Block(); + Block b9 = new Block(); + + b0.setCode(new Instruction[] { + Instruction.forOpcode(opc_jsr) + }, new Block[] { b2, b1 }); + b1.setCode(new Instruction[] { + Instruction.forOpcode(opc_jsr) + }, new Block[] { b5, null }); + b2.setCode(new Instruction[] { + Instruction.forOpcode(opc_astore, LocalVariableInfo.getInfo(2)), + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ifeq) + }, new Block[] { b3, b7 }); + b3.setCode(new Instruction[] { + Instruction.forOpcode(opc_jsr) + }, new Block[] { b5, b1 }); + b4.setCode(new Instruction[] { + Instruction.forOpcode(opc_ret, LocalVariableInfo.getInfo(2)), + }, new Block[0]); + b5.setCode(new Instruction[] { + Instruction.forOpcode(opc_astore, LocalVariableInfo.getInfo(3)), + Instruction.forOpcode(opc_ret, LocalVariableInfo.getInfo(3)), + }, new Block[0]); + b6.setCode(new Instruction[] { + Instruction.forOpcode(opc_astore, LocalVariableInfo.getInfo(3)) + }, new Block[] { b4 }); + b7.setCode(new Instruction[] { + Instruction.forOpcode(opc_iload, LocalVariableInfo.getInfo(1)), + Instruction.forOpcode(opc_ifeq) + }, new Block[] { b8, b4 }); + b8.setCode(new Instruction[] { + Instruction.forOpcode(opc_jsr) + }, new Block[] { b6, b9 }); + b9.setCode(new Instruction[0], new Block[] { b7 }); + + BasicBlocks bb = new BasicBlocks(new MethodInfo("foo", "(I)V", 0)); + bb.setBlocks(new Block[] { b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 }, + b0, new Handler[0]); + ca.analyzeCode(null, bb); + + BitSet reachable = (BitSet) ca.bbInfos.get(bb); + assertEquals("Reachable set", + "{0, 1, 2, 3, 4, 5, 6, 7, 8}", reachable.toString()); + assertNotNull("Constant Flow", + ca.constantInfos.get(b8.getInstructions()[0])); + + ca.transformCode(bb); + + Block[] blocks = bb.getBlocks(); + assertEquals(9, blocks.length); + assertEquals(2, blocks[0].getSuccs().length); + assertEquals(2, blocks[1].getSuccs().length); + assertEquals(2, blocks[3].getSuccs().length); + assertEquals(1, blocks[8].getSuccs().length); + } + + public static Test suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new ConstAnaTest("testSimple")); + suite.addTest(new ConstAnaTest("testJsr")); + suite.addTest(new ConstAnaTest("testNestedJsr")); + return suite; + } +}