001: /*
002: * FindBugs - Find bugs in Java programs
003: * Copyright (C) 2003,2004 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.detect;
021:
022: import org.apache.bcel.Constants;
023: import org.apache.bcel.generic.ConstantPoolGen;
024: import org.apache.bcel.generic.Instruction;
025: import org.apache.bcel.generic.InstructionHandle;
026: import org.apache.bcel.generic.InvokeInstruction;
027:
028: import edu.umd.cs.findbugs.ba.BasicBlock;
029: import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
030: import edu.umd.cs.findbugs.ba.Location;
031: import edu.umd.cs.findbugs.ba.ResourceValue;
032: import edu.umd.cs.findbugs.ba.ResourceValueFrame;
033: import edu.umd.cs.findbugs.ba.ResourceValueFrameModelingVisitor;
034:
035: /**
036: * A visitor to model the effect of instructions on the status
037: * of the resource (in this case, Streams).
038: */
039: public class StreamFrameModelingVisitor extends
040: ResourceValueFrameModelingVisitor {
041: private StreamResourceTracker resourceTracker;
042: private Stream stream;
043: private Location location;
044:
045: public StreamFrameModelingVisitor(ConstantPoolGen cpg,
046: StreamResourceTracker resourceTracker, Stream stream) {
047: super (cpg);
048: this .resourceTracker = resourceTracker;
049: this .stream = stream;
050: }
051:
052: @Override
053: public void transferInstruction(InstructionHandle handle,
054: BasicBlock basicBlock) throws DataflowAnalysisException {
055: // Record what Location we are analyzing
056: this .location = new Location(handle, basicBlock);
057:
058: final Instruction ins = handle.getInstruction();
059: final ConstantPoolGen cpg = getCPG();
060: final ResourceValueFrame frame = getFrame();
061:
062: int status = -1;
063: boolean created = false;
064:
065: // Is a resource created, opened, or closed by this instruction?
066: Location creationPoint = stream.getLocation();
067: if (handle == creationPoint.getHandle()
068: && basicBlock == creationPoint.getBasicBlock()) {
069: // Resource creation
070: if (stream.isOpenOnCreation()) {
071: status = ResourceValueFrame.OPEN;
072: stream.setOpenLocation(location);
073: resourceTracker.addStreamOpenLocation(location, stream);
074: } else {
075: status = ResourceValueFrame.CREATED;
076: }
077: created = true;
078: } else if (resourceTracker.isResourceOpen(basicBlock, handle,
079: cpg, stream, frame)) {
080: // Resource opened
081: status = ResourceValueFrame.OPEN;
082: stream.setOpenLocation(location);
083: resourceTracker.addStreamOpenLocation(location, stream);
084: } else if (resourceTracker.isResourceClose(basicBlock, handle,
085: cpg, stream, frame)) {
086: // Resource closed
087: status = ResourceValueFrame.CLOSED;
088: }
089:
090: // Model use of instance values in frame slots
091: analyzeInstruction(ins);
092:
093: // If needed, update frame status
094: if (status != -1) {
095: frame.setStatus(status);
096: if (created)
097: frame.setValue(frame.getNumSlots() - 1, ResourceValue
098: .instance());
099: }
100:
101: }
102:
103: @Override
104: protected boolean instanceEscapes(InvokeInstruction inv,
105: int instanceArgNum) {
106: ConstantPoolGen cpg = getCPG();
107: String className = inv.getClassName(cpg);
108:
109: //System.out.print("[Passed as arg="+instanceArgNum+" at " + inv + "]");
110:
111: boolean escapes = (inv.getOpcode() == Constants.INVOKESTATIC || instanceArgNum != 0);
112: String methodName = inv.getMethodName(cpg);
113: String methodSig = inv.getSignature(cpg);
114: if (inv.getOpcode() == Constants.INVOKEVIRTUAL
115: && (methodName.equals("load")
116: || methodName.equals("loadFromXml")
117: || methodName.equals("store") || methodName
118: .equals("save"))
119: && className.equals("java.util.Properties"))
120: escapes = false;
121: if (inv.getOpcode() == Constants.INVOKEVIRTUAL
122: && (methodName.equals("load") || methodName
123: .equals("store"))
124: && className.equals("java.security.KeyStore"))
125: escapes = false;
126: if (inv.getOpcode() == Constants.INVOKEVIRTUAL
127: && "getChannel".equals(methodName)
128: && "()Ljava/nio/channels/FileChannel;"
129: .equals(methodSig))
130: escapes = true;
131:
132: if (FindOpenStream.DEBUG && escapes) {
133: System.out.println("ESCAPE at " + location + " at call to "
134: + className + "." + methodName + ":" + methodSig);
135: }
136:
137: // Record the fact that this might be a stream escape
138: if (stream.getOpenLocation() != null)
139: resourceTracker.addStreamEscape(stream, location);
140:
141: return escapes;
142: }
143: }
144:
145: // vim:ts=3
|