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.ARRAYLENGTH;
032: import static org.objectweb.asm.Opcodes.GETFIELD;
033: import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
034: import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
035: import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
036: import static org.objectweb.asm.Opcodes.MONITORENTER;
037: import static org.objectweb.asm.Opcodes.MONITOREXIT;
038: import static org.objectweb.asm.Opcodes.PUTFIELD;
039: import static org.objectweb.asm.tree.analysis.BasicValue.REFERENCE_VALUE;
040:
041: import java.util.ArrayList;
042: import java.util.List;
043:
044: import org.objectweb.asm.Type;
045: import org.objectweb.asm.tree.AbstractInsnNode;
046: import org.objectweb.asm.tree.MethodInsnNode;
047: import org.objectweb.asm.tree.MethodNode;
048: import org.objectweb.asm.tree.analysis.Analyzer;
049: import org.objectweb.asm.tree.analysis.AnalyzerException;
050: import org.objectweb.asm.tree.analysis.BasicInterpreter;
051: import org.objectweb.asm.tree.analysis.BasicValue;
052: import org.objectweb.asm.tree.analysis.Frame;
053: import org.objectweb.asm.tree.analysis.Value;
054:
055: /**
056: * ASM Guide example class.
057: *
058: * @author Eric Bruneton
059: */
060: public class NullDereferenceAnalyzer {
061:
062: public List<AbstractInsnNode> findNullDereferences(String owner,
063: MethodNode mn) throws AnalyzerException {
064: List<AbstractInsnNode> result = new ArrayList<AbstractInsnNode>();
065: Analyzer a = new Analyzer(new IsNullInterpreter());
066: a.analyze(owner, mn);
067: Frame[] frames = a.getFrames();
068: AbstractInsnNode[] insns = mn.instructions.toArray();
069: for (int i = 0; i < insns.length; ++i) {
070: AbstractInsnNode insn = insns[i];
071: if (frames[i] != null) {
072: Value v = getTarget(insn, frames[i]);
073: if (v == IsNullInterpreter.NULL
074: || v == IsNullInterpreter.MAYBENULL) {
075: result.add(insn);
076: }
077: }
078: }
079: return result;
080: }
081:
082: private static Value getTarget(AbstractInsnNode insn, Frame f) {
083: switch (insn.getOpcode()) {
084: case GETFIELD:
085: case ARRAYLENGTH:
086: case MONITORENTER:
087: case MONITOREXIT:
088: return getStackValue(f, 0);
089: case PUTFIELD:
090: return getStackValue(f, 1);
091: case INVOKEVIRTUAL:
092: case INVOKESPECIAL:
093: case INVOKEINTERFACE:
094: String desc = ((MethodInsnNode) insn).desc;
095: return getStackValue(f, Type.getArgumentTypes(desc).length);
096: }
097: return null;
098: }
099:
100: private static Value getStackValue(Frame f, int index) {
101: int top = f.getStackSize() - 1;
102: return index <= top ? f.getStack(top - index) : null;
103: }
104: }
105:
106: class IsNullInterpreter extends BasicInterpreter {
107:
108: public final static BasicValue NULL = new BasicValue(null);
109:
110: public final static BasicValue MAYBENULL = new BasicValue(null);
111:
112: @Override
113: public Value newOperation(AbstractInsnNode insn) {
114: if (insn.getOpcode() == ACONST_NULL) {
115: return NULL;
116: }
117: return super .newOperation(insn);
118: }
119:
120: @Override
121: public Value merge(Value v, Value w) {
122: if (isRef(v) && isRef(w) && v != w) {
123: return MAYBENULL;
124: }
125: return super .merge(v, w);
126: }
127:
128: private boolean isRef(Value v) {
129: return v == REFERENCE_VALUE || v == NULL || v == MAYBENULL;
130: }
131: }
|