Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2013 Dave Brosius
   * 
   * 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 com.mebigfatguy.fbcontrib.detect;
 
 import java.util.Map;
 import java.util.Set;
 
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.JavaClass;
 import  org.apache.bcel.generic.Type;
 
 
 import  edu.umd.cs.findbugs.BugInstance;
 import  edu.umd.cs.findbugs.BugReporter;
 import  edu.umd.cs.findbugs.BytecodeScanningDetector;
 import  edu.umd.cs.findbugs.OpcodeStack;
 import  edu.umd.cs.findbugs.ba.ClassContext;
 import  edu.umd.cs.findbugs.ba.XMethod;

looks for methods that rely on the format of the string fetched from another object's toString method, when that method appears not to be owned by the author of the calling method. As the implementation of toString() is often considered a private implementation detail of a class, and not something that should be relied on, depending on it's format is dangerous.
 
 public class InappropriateToStringUse extends BytecodeScanningDetector {
 
 	private static final Set<StringvalidToStringClasses = new HashSet<String>();
 	static {
 		.add("java/lang/Object"); // too many fps
 		.add("java/lang/Byte");
 		.add("java/lang/Character");
 		.add("java/lang/Short");
 		.add("java/lang/Integer");
 		.add("java/lang/Boolean");
 		.add("java/lang/Float");
 		.add("java/lang/Double");
 		.add("java/lang/Long");
 		.add("java/lang/String");
 		.add("java/lang/Number");
 		.add("java/lang/StringBuffer");
 		.add("java/lang/StringBuilder");
 		.add("java/io/StringWriter");
 	}
 	private static final Set<StringstringAlgoMethods = new HashSet<String>();
 	static {
 		.add("indexOf");
 		.add("contains");
 		.add("startsWith");
 		.add("endsWith");
 		.add("substring");
 	}
 
 	private final BugReporter bugReporter;
 	private OpcodeStack stack;
 	private String packageName;

constructs a ITU detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 
 	public InappropriateToStringUse(BugReporter bugReporter) {
 		this. = bugReporter;
 	}

overrides the visitor to reset the stack

Parameters:
classContext the context object of the currently parsed class
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			 = new OpcodeStack();
 			 = classContext.getJavaClass().getPackageName();
 			super.visitClassContext(classContext);
finally {
			 = null;
		}
	}

overrides the visitor to resets the stack for this method.

Parameters:
obj the context object for the currently parsed code block
	public void visitCode(Code obj) {
		.resetForMethodEntry(this);
		super.visitCode(obj);
	}

overrides the visitor to look for suspicious operations on toString
	public void sawOpcode(int seen) {
		String methodPackage = null;
		try {
			if (seen == INVOKEVIRTUAL) {
				String methodName = getNameConstantOperand();
				if ("toString".equals(methodName)) {
					String signature = getSigConstantOperand();
					if ("()Ljava/lang/String;".equals(signature)) {
						if (!.contains(className)) {
							if (.getStackDepth() > 0) {
								OpcodeStack.Item item = .getStackItem(0);
								JavaClass cls = item.getJavaClass();
								if (cls != null) {
									methodPackage = cls.getPackageName();
								}
							}
						}
					}
else if (.contains(methodName)) {
					if ("java/lang/String".equals(className)) {
						String signature = getSigConstantOperand();
						int numParms = Type.getArgumentTypes(signature).length;
						if (.getStackDepth() > numParms) {
							OpcodeStack.Item item = .getStackItem(numParms);
							if (item.getUserValue() != null) {
								XMethod xm = item.getReturnValueOf();
								String tsPackage = null;
								if (xm != null) {
									tsPackage = xm.getPackageName();
								}
								if ((tsPackage == null) || !SignatureUtils.similarPackages(tsPackage, 2)) {
									.reportBug(new BugInstance(this"ITU_INAPPROPRIATE_TOSTRING_USE", NORMAL_PRIORITY)
									.addClass(this)
									.addMethod(this)
									.addSourceLine(this));
								}
							}
						}
					}
				}
else if ((seen == ASTORE)
					||  ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item item = .getStackItem(0);
					Integer reg = Integer.valueOf(RegisterUtils.getAStoreReg(thisseen));
					if (item.getUserValue() != null) {
						XMethod xm = item.getReturnValueOf();
						if (xm != null) {
							.put(regxm.getPackageName());
else {
						}
else {
					}
				}
else if ((seen == ALOAD)
					||  ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
				Integer reg = Integer.valueOf(RegisterUtils.getAStoreReg(thisseen));
				methodPackage = .get(reg);
			}
catch (ClassNotFoundException cnfe) {
			.reportMissingClass(cnfe);
finally {
			TernaryPatcher.pre(seen);
			.sawOpcode(thisseen);
			TernaryPatcher.post(seen);
			if (methodPackage != null) {
				if (.getStackDepth() > 0) {
					OpcodeStack.Item item = .getStackItem(0);
					item.setUserValue(methodPackage);
				}
			}
		}
	}
New to GrepCode? Check out our FAQ X