Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2014 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.classfile.Method;
 
 
looks for method calls through reflection on methods found in java.lang.Object. As these methods are always available, there's no reason to do this.
 
 public class ReflectionOnObjectMethods extends BytecodeScanningDetector {
 
 	private static final Set<StringobjectSigs = new HashSet<String>();
 	static {
 		//objectSigs.add("clone()"); // clone is declared protected
 		.add("equals(Ljava/lang/Object;)");
 		.add("finalize()");
 		.add("getClass()");
 		.add("hashCode()");
 		.add("notify()");
 		.add("notifyAll()");
 		.add("toString()");
 		.add("wait");
 		.add("wait(J)");
 		.add("wait(JI");
 
 
 	}
 	private final BugReporter bugReporter;
 	private OpcodeStack stack;
 	private Map<IntegerString[]> localClassTypes;
 	private Map<StringString[]> fieldClassTypes;

constructs a ROOM detector given the reporter to report bugs on

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

implements the visitor to create the stack and local and field maps for Class arrays to be used for getting the reflection method

Parameters:
classContext the context object of the currently parse class
 
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			 = new OpcodeStack();
 			JavaClass cls = classContext.getJavaClass();
 			Method staticInit = findStaticInitializer(cls);
 			if (staticInit != null) {
 				setupVisitorForClass(cls);
 				doVisitMethod(staticInit);
 			}
 
 			super.visitClassContext(classContext);
 		} finally {
 			 = null;
 			 = null;
		}
	}

implements the visitor to reset the opcode stack and clear the local variable map@

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

implements the visitor to look for calls that invoke a method through reflection where the method is defined in java.lang.Object

Parameters:
seen the currently parsed opcode
	public void sawOpcode(int seen) {
		Integer arraySize = null;
		String[] loadedTypes = null;
		try {
	        .precomputation(this);
	        
			switch (seen) {
				case ANEWARRAY: {
					if ("java/lang/Class".equals(getClassConstantOperand())) {
						if (.getStackDepth() >= 1) {
							arraySize = (Integer)item.getConstant();
						}
					}
				}
				break;
				case AASTORE: {
					if (.getStackDepth() >= 3) {
						String[] arrayTypes = (String[])arrayItem.getUserValue();
						if (arrayTypes != null) {
							String type = (String)valueItem.getConstant();
							if (type != null) {
								Integer index = (Integer)indexItem.getConstant();
								if (index != null) {
									arrayTypes[index.intValue()] = type;
								}
							}
						}
					}
				}
				break;
				case PUTFIELD:
				case PUTSTATIC: {
					if (.getStackDepth() >= 1) {
						String[] arrayTypes = (String[])item.getUserValue();
						if (arrayTypes != null) {
							.put(namearrayTypes);
							return;
						}
					}
				}
				break;
				case GETFIELD:
				case GETSTATIC: {
					loadedTypes = .get(name);
				}
				break;
				case ASTORE_0:
				case ASTORE_1:
				case ASTORE_2:
				case ASTORE_3:
				case ASTORE: {
					Integer reg = Integer.valueOf(RegisterUtils.getAStoreReg(thisseen));
					if (.getStackDepth() >= 1) {
						String[] arrayTypes = (String[])item.getUserValue();
						if (arrayTypes != null) {
							.put(regarrayTypes);
							return;
						}
					}
				}
				break;
				case ALOAD_0:
				case ALOAD_1:
				case ALOAD_2:
				case ALOAD_3:
				case ALOAD: {
					int reg = RegisterUtils.getAStoreReg(thisseen);
					loadedTypes = .get(Integer.valueOf(reg));
				}
				break;
				case INVOKEVIRTUAL: {
					if ("java/lang/Class".equals(cls)) {
						if ("getMethod".equals(method)) {
							if ("(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;".equals(sig)) {
								if (.getStackDepth() >= 2) {
									String[] arrayTypes = (String[])clsArgs.getUserValue();
									if ((arrayTypes != null) || (clsArgs.isNull())) {
										OpcodeStack.Item methodItem = .getStackItem(1);
										String methodName = (String)methodItem.getConstant();
										if (methodName != null) {
											String reflectionSig = buildReflectionSignature(methodNamearrayTypes);
											if (.contains(reflectionSig)) {
												loadedTypes = (arrayTypes == null) ? new String[0] : arrayTypes;
											}
										}
									}
								}
							}
						}
else if ("java/lang/reflect/Method".equals(cls)) {
						if ("invoke".equals(method)) {
							if (.getStackDepth() >= 3) {
								OpcodeStack.Item methodItem = .getStackItem(2);
								String[] arrayTypes = (String[])methodItem.getUserValue();
								if (arrayTypes != null) {
									.reportBug(new BugInstance(this"ROOM_REFLECTION_ON_OBJECT_METHODS", NORMAL_PRIORITY)
												.addClass(this)
												.addMethod(this)
												.addSourceLine(this));
								}
							}
						}
					}
				}
				break;
			}
finally {
			TernaryPatcher.pre(seen);
			.sawOpcode(thisseen);
			TernaryPatcher.post(seen);
			if (arraySize != null) {
				if (.getStackDepth() >= 1) {
					item.setUserValue(new String[arraySize.intValue()]);
				}
else if (loadedTypes != null) {
				if (.getStackDepth() >= 1) {
					item.setUserValue(loadedTypes);
				}
			}
		}
	}

builds a string that represents the signature of the method call that is being executed though reflection.

Parameters:
methodName the method name
parmTypes the array of parameter types of the method
Returns:
a signature string minus the return type
	private String buildReflectionSignature(String methodNameString[] parmTypes) {
		StringBuilder sb = new StringBuilder(64);
		sb.append(methodName);
		sb.append("(");
		if (parmTypes != null) {
			for (String type : parmTypes) {
				sb.append("L");
				if (type == null) {
					return "";
				}
				sb.append(type);
				if ((type.length() > 1) || ("IJ".indexOf(type) < 0)) {
					sb.append(";");
				}
			}
		}
		sb.append(")");
		return sb.toString();
	}

finds the method that is the static initializer for the class

Parameters:
cls the class to find the initializer for
Returns:
the Method of the static initializer or null if this class has none
	private Method findStaticInitializer(JavaClass cls) {
		Method[] methods = cls.getMethods();
		for (Method m : methods) {
			if ("<clinit>".equals(m.getName())) {
				return m;
			}
		}
		return null;
	}
New to GrepCode? Check out our FAQ X