/* * 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.security.MessageDigest; import java.security.NoSuchAlgorithmException; import org.apache.bcel.classfile.Code; import edu.umd.cs.findbugs.BugAccumulator; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.bcel.OpcodeStackDetector; import edu.umd.cs.findbugs.core.Priorities; public class Noise extends OpcodeStackDetector { class HashQueue { HashQueue(int size) throws NoSuchAlgorithmException { md = MessageDigest.getInstance("SHA"); this.size = size; this.data = new byte[size]; } MessageDigest md; final int size; int next = 0; // 0 <= next < size final byte[] data; // data is next..size-1, 0..next-1 public void push(byte b) { data[next++] = b; if (next == size) next = 0; } public void reset() { next = 0; for (int i = 0; i < size; i++) data[i] = 0; } public void push(String s) { for (byte b : s.getBytes()) push(b); } public void pushHash(Object x) { push(x.hashCode()); } public void push(int x) { push((byte) (x)); push((byte) (x >> 8)); push((byte) (x >> 16)); push((byte) (x >> 24)); } public int getHash() { md.update(primer); md.update(data, next, size - next); md.update(data, 0, next); byte[] hash = md.digest(); int result = (hash[0] & 0xff) | (hash[1] & 0xff) << 8 | (hash[2] & 0xff) << 16 | (hash[3] & 0x7f) << 24; return result; } public int getPriority() { int hash = getHash(); if ((hash & 0x1ff0) == 0) { hash = hash & 0xf; if (hash < 1) return Priorities.HIGH_PRIORITY; else if (hash < 1 + 2) return Priorities.NORMAL_PRIORITY; else if (hash < 1 + 2 + 4) return Priorities.LOW_PRIORITY; else return Priorities.IGNORE_PRIORITY; } else return Priorities.IGNORE_PRIORITY + 1; } } final BugReporter bugReporter; final BugAccumulator accumulator; final HashQueue hq; byte[] primer; public Noise(BugReporter bugReporter) throws NoSuchAlgorithmException { this.bugReporter = bugReporter; this.accumulator = new BugAccumulator(bugReporter); hq = new HashQueue(24); } @Override public void visit(Code code) { primer = getFullyQualifiedMethodName().getBytes(); hq.reset(); super.visit(code); // make callbacks to sawOpcode for all opcodes accumulator.reportAccumulatedBugs(); } @Override public void sawInt(int i) { hq.push(i); } @Override public void sawLong(long x) { hq.push((int) (x >> 0)); hq.push((int) (x >> 32)); } @Override public void sawString(String s) { hq.pushHash(s); } @Override public void sawClass() { hq.push(getClassConstantOperand()); } /* * (non-Javadoc) * * @see edu.umd.cs.findbugs.bcel.OpcodeStackDetector#sawOpcode(int) */ @Override public void sawOpcode(int seen) { int priority; switch (seen) { case INVOKEINTERFACE: case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: hq.pushHash(getClassConstantOperand()); if (getNameConstantOperand().indexOf('$') == -1) hq.pushHash(getNameConstantOperand()); hq.pushHash(getSigConstantOperand()); priority = hq.getPriority(); if (priority <= Priorities.LOW_PRIORITY) accumulator.accumulateBug(new BugInstance(this, "NOISE_METHOD_CALL", priority).addClassAndMethod(this) .addCalledMethod(this), this); break; case GETFIELD: case PUTFIELD: case GETSTATIC: case PUTSTATIC: hq.pushHash(getClassConstantOperand()); if (getNameConstantOperand().indexOf('$') == -1) hq.pushHash(getNameConstantOperand()); hq.pushHash(getSigConstantOperand()); priority = hq.getPriority(); if (priority <= Priorities.LOW_PRIORITY) accumulator.accumulateBug(new BugInstance(this, "NOISE_FIELD_REFERENCE", priority).addClassAndMethod(this) .addReferencedField(this), this); break; case CHECKCAST: case INSTANCEOF: case NEW: hq.pushHash(getClassConstantOperand()); break; case IFEQ: case IFNE: case IFNONNULL: case IFNULL: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLE: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLT: case IF_ACMPEQ: case IF_ACMPNE: case RETURN: case ARETURN: case IRETURN: case MONITORENTER: case MONITOREXIT: case IINC: case NEWARRAY: case TABLESWITCH: case LOOKUPSWITCH: case LCMP: case INEG: case IADD: case IMUL: case ISUB: case IDIV: case IREM: case IXOR: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case LAND: case LOR: case LADD: case LMUL: case LSUB: case LDIV: case LSHL: case LSHR: case LUSHR: case AALOAD: case AASTORE: case IALOAD: case IASTORE: case BALOAD: case BASTORE: hq.push(seen); priority = hq.getPriority(); if (priority <= Priorities.LOW_PRIORITY) accumulator.accumulateBug( new BugInstance(this, "NOISE_OPERATION", priority).addClassAndMethod(this).addString(OPCODE_NAMES[seen]), this); } } }