001: /***
002: * ASM Guide
003: * Copyright (c) 2007 Eric Bruneton
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: * 1. Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: * 2. Redistributions in binary form must reproduce the above copyright
012: * notice, this list of conditions and the following disclaimer in the
013: * documentation and/or other materials provided with the distribution.
014: * 3. Neither the name of the copyright holders nor the names of its
015: * contributors may be used to endorse or promote products derived from
016: * this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028: * THE POSSIBILITY OF SUCH DAMAGE.
029: */package ch7.sec2;
030:
031: import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
032: import static org.objectweb.asm.Opcodes.ACONST_NULL;
033: import static org.objectweb.asm.Opcodes.ALOAD;
034: import static org.objectweb.asm.Opcodes.ASTORE;
035: import static org.objectweb.asm.Opcodes.ATHROW;
036: import static org.objectweb.asm.Opcodes.DUP;
037: import static org.objectweb.asm.Opcodes.GETFIELD;
038: import static org.objectweb.asm.Opcodes.GOTO;
039: import static org.objectweb.asm.Opcodes.IADD;
040: import static org.objectweb.asm.Opcodes.ICONST_1;
041: import static org.objectweb.asm.Opcodes.IFEQ;
042: import static org.objectweb.asm.Opcodes.ILOAD;
043: import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
044: import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
045: import static org.objectweb.asm.Opcodes.MONITORENTER;
046: import static org.objectweb.asm.Opcodes.MONITOREXIT;
047: import static org.objectweb.asm.Opcodes.NEW;
048: import static org.objectweb.asm.Opcodes.PUTFIELD;
049: import static org.objectweb.asm.Opcodes.RETURN;
050:
051: import java.util.List;
052:
053: import org.objectweb.asm.ClassVisitor;
054: import org.objectweb.asm.Label;
055: import org.objectweb.asm.tree.AbstractInsnNode;
056: import org.objectweb.asm.tree.ClassNode;
057: import org.objectweb.asm.tree.MethodNode;
058: import org.objectweb.asm.tree.analysis.AnalyzerException;
059:
060: import util.AbstractTestCase;
061:
062: /**
063: * ASM Guide example test class.
064: *
065: * @author Eric Bruneton
066: */
067: public class NullDereferenceAnalyzerTest extends AbstractTestCase {
068:
069: public void test() throws Exception {
070: MethodNode mn = new MethodNode(ACC_PUBLIC, "m", "(ZZ)V", null,
071: null);
072: mn.visitCode();
073: Label l0 = new Label();
074: Label l1 = new Label();
075: Label l2 = new Label();
076: Label l3 = new Label();
077: Label l4 = new Label();
078: Label l5 = new Label();
079: Label l6 = new Label();
080: mn.visitTryCatchBlock(l0, l1, l2, null);
081: mn.visitTryCatchBlock(l2, l3, l2, null);
082: mn.visitInsn(ACONST_NULL); // insn 0
083: mn.visitVarInsn(ASTORE, 3);
084: mn.visitInsn(ACONST_NULL); // insn 2
085: mn.visitVarInsn(ASTORE, 4);
086: mn.visitTypeInsn(NEW, "C");
087: mn.visitInsn(DUP);
088: mn.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
089: mn.visitVarInsn(ASTORE, 5);
090: mn.visitVarInsn(ILOAD, 1);
091: mn.visitJumpInsn(IFEQ, l4);
092: mn.visitTypeInsn(NEW, "java/lang/Integer"); // insn
093: // 10
094: mn.visitInsn(DUP);
095: mn.visitInsn(ICONST_1);
096: mn.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer",
097: "<init>", "(I)V");
098: mn.visitVarInsn(ASTORE, 3);
099: mn.visitTypeInsn(NEW, "C"); // insn 15
100: mn.visitInsn(DUP);
101: mn.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
102: mn.visitVarInsn(ASTORE, 4);
103: mn.visitLabel(l4);
104: mn.visitVarInsn(ILOAD, 2);
105: mn.visitJumpInsn(IFEQ, l5);
106: mn.visitTypeInsn(NEW, "java/lang/Integer"); // insn
107: // 22
108: mn.visitInsn(DUP);
109: mn.visitInsn(ICONST_1);
110: mn.visitMethodInsn(INVOKESPECIAL, "java/lang/Integer",
111: "<init>", "(I)V");
112: mn.visitVarInsn(ASTORE, 3);
113: mn.visitTypeInsn(NEW, "C"); // insn 27
114: mn.visitInsn(DUP);
115: mn.visitMethodInsn(INVOKESPECIAL, "C", "<init>", "()V");
116: mn.visitVarInsn(ASTORE, 4);
117: mn.visitLabel(l5);
118: mn.visitVarInsn(ALOAD, 4);
119: mn.visitInsn(DUP);
120: mn.visitVarInsn(ASTORE, 6);
121: mn.visitInsn(MONITORENTER); // insn 35
122: mn.visitLabel(l0);
123: mn.visitVarInsn(ALOAD, 4);
124: mn.visitVarInsn(ALOAD, 4);
125: mn.visitFieldInsn(GETFIELD, "C", "i", "I"); // insn
126: // 39
127: mn.visitVarInsn(ALOAD, 5);
128: mn.visitFieldInsn(GETFIELD, "C", "i", "I");
129: mn.visitInsn(IADD);
130: mn.visitVarInsn(ALOAD, 3);
131: mn.visitMethodInsn(INVOKEVIRTUAL, // insn 44
132: "java/lang/Integer", "intValue", "()I");
133: mn.visitInsn(IADD);
134: mn.visitFieldInsn(PUTFIELD, "C", "i", "I"); // insn
135: // 46
136: mn.visitVarInsn(ALOAD, 6);
137: mn.visitInsn(MONITOREXIT); // insn 48
138: mn.visitLabel(l1);
139: mn.visitJumpInsn(GOTO, l6);
140: mn.visitLabel(l2);
141: mn.visitVarInsn(ALOAD, 6);
142: mn.visitInsn(MONITOREXIT); // insn 53
143: mn.visitLabel(l3);
144: mn.visitInsn(ATHROW);
145: mn.visitLabel(l6);
146: mn.visitInsn(RETURN);
147: mn.visitMaxs(3, 7);
148: mn.visitEnd();
149:
150: List<AbstractInsnNode> occurences;
151: occurences = new NullDereferenceAnalyzer()
152: .findNullDereferences("D", mn);
153: assertEquals(6, occurences.size());
154: assertTrue(occurences.contains(mn.instructions.get(35)));
155: assertTrue(occurences.contains(mn.instructions.get(39)));
156: assertTrue(occurences.contains(mn.instructions.get(44)));
157: assertTrue(occurences.contains(mn.instructions.get(46)));
158: assertTrue(occurences.contains(mn.instructions.get(48)));
159: assertTrue(occurences.contains(mn.instructions.get(53)));
160: }
161:
162: @Override
163: protected ClassVisitor getClassAdapter(final ClassVisitor cv) {
164: return new ClassNode() {
165: @Override
166: public void visitEnd() {
167: for (MethodNode mn : (List<MethodNode>) methods) {
168: try {
169: new NullDereferenceAnalyzer()
170: .findNullDereferences(name, mn);
171: } catch (AnalyzerException e) {
172: }
173: }
174: accept(cv);
175: }
176: };
177: }
178:
179: // source code used to get above ASMified code
180:
181: public void m(boolean a, boolean b) {
182: Integer i = null;
183: C c = null;
184: C d = new C();
185: if (a) {
186: i = new Integer(1);
187: c = new C();
188: }
189: if (b) {
190: i = new Integer(1);
191: c = new C();
192: }
193: synchronized (c) { // c may be null
194: c.i = c.i + d.i + i.intValue(); // c and i may
195: // be null, but
196: // not d
197: }
198: }
199:
200: static class C {
201: int i;
202: }
203: }
|