/* * FindBugs - Find bugs in Java programs * Copyright (C) 2004-2006 University of Maryland * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.umd.cs.findbugs.detect; import java.util.Set; import org.apache.bcel.classfile.Constant; import org.apache.bcel.classfile.ConstantClass; import org.apache.bcel.classfile.ConstantString; import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.classfile.Method; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.BytecodeScanningDetector; import edu.umd.cs.findbugs.StatelessDetector; import edu.umd.cs.findbugs.ba.AnalysisContext; //import edu.umd.cs.findbugs.ba.ch.Subtypes; import edu.umd.cs.findbugs.ba.ch.Subtypes2; import edu.umd.cs.findbugs.classfile.ClassDescriptor; public class InheritanceUnsafeGetResource extends BytecodeScanningDetector implements StatelessDetector { private BugReporter bugReporter; private boolean classIsFinal; // private boolean methodIsVisibleToOtherPackages; private boolean classIsVisibleToOtherPackages; // private boolean methodIsFinal; private boolean methodIsStatic; int state = 0; int sawGetClass; boolean reportedForThisClass; String stringConstant; int prevOpcode; public InheritanceUnsafeGetResource(BugReporter bugReporter) { this.bugReporter = bugReporter; } @Override public void visit(JavaClass obj) { classIsFinal = obj.isFinal(); reportedForThisClass = false; classIsVisibleToOtherPackages = obj.isPublic() || obj.isProtected(); } @Override public void visit(Method obj) { methodIsStatic = obj.isStatic(); state = 0; sawGetClass = -100; } @Override public void sawOpcode(int seen) { if (reportedForThisClass) return; switch (seen) { case LDC: Constant constantValue = getConstantRefOperand(); if (constantValue instanceof ConstantClass) sawGetClass = -100; else if (constantValue instanceof ConstantString) { stringConstant = ((ConstantString)constantValue).getBytes(getConstantPool()); } break; case ALOAD_0: state = 1; break; case INVOKEVIRTUAL: if (getClassConstantOperand().equals("java/lang/Class") && (getNameConstantOperand().equals("getResource") || getNameConstantOperand().equals("getResourceAsStream")) && sawGetClass + 10 >= getPC()) { int priority = NORMAL_PRIORITY; if (prevOpcode == LDC && stringConstant != null && stringConstant.charAt(0)=='/') priority = LOW_PRIORITY; else { priority = adjustPriority(priority); } bugReporter.reportBug(new BugInstance(this, "UI_INHERITANCE_UNSAFE_GETRESOURCE", priority) .addClassAndMethod(this) .addSourceLine(this)); reportedForThisClass = true; } else if (state == 1 && !methodIsStatic && !classIsFinal && classIsVisibleToOtherPackages && getNameConstantOperand().equals("getClass") && getSigConstantOperand().equals("()Ljava/lang/Class;")) { sawGetClass = getPC(); } state = 0; break; default: state = 0; break; } if (seen != LDC) stringConstant = null; prevOpcode = seen; } /** * Adjust the priority of a warning about to be reported. * * @param priority initial priority * @return adjusted priority */ private int adjustPriority(int priority) { // if (Subtypes.DO_NOT_USE) { // Use Subtypes2 instead of (deprecated) Subtypes try { Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2(); if (!subtypes2.hasSubtypes(getClassDescriptor())) { priority++; } else { Set<ClassDescriptor> mySubtypes = subtypes2.getSubtypes(getClassDescriptor()); String myPackagename = getThisClass().getPackageName(); for (ClassDescriptor c : mySubtypes) { if (c.equals(getClassDescriptor())) { continue; } if (!c.getPackageName().equals(myPackagename)) { priority--; break; } } } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } // } else { // Subtypes subtypes = AnalysisContext.currentAnalysisContext().getSubtypes(); // String myPackagename = getThisClass().getPackageName(); // Set<JavaClass> mySubtypes = subtypes.getTransitiveSubtypes(getThisClass()); // if (mySubtypes.isEmpty()) { // priority++; // } else { // for(JavaClass c : mySubtypes) { // if (!c.getPackageName().equals(myPackagename)) { // priority--; // break; // } // } // } // } return priority; } }