/** * @param methodDescriptor */ private void sawNoSideEffectCall(MethodDescriptor methodDescriptor) { if(uselessVoidCandidate && Type.getReturnType(methodDescriptor.getSignature()) == Type.VOID && !methodDescriptor.getName().equals(Const.CONSTRUCTOR_NAME)) { /* To reduce false-positives we do not mark method as useless void if it calls * another useless void method. If that another method also in the scope of our project * then we will report it instead. If there's a cycle of no-side-effect calls, then * it's probably some delegation pattern and methods can be extended in future/derived * projects to do something useful. */ uselessVoidCandidate = false; } }
} else { Type returnType = Type.getReturnType(xmethod.getSignature()); if (returnType instanceof ObjectType) { try {
boolean propagateToReturnValue(Set<ValueInfo> vals, ValueNumber vn, GenLocation location, MethodDescriptor m) throws DataflowAnalysisException { for(ValueInfo vi : vals) { if(vi.type.getSignature().startsWith("[") && vi.hasObjectOnlyCall && vi.var == null && vn.getNumber() == vi.origValue) { // Ignore initialized arrays passed to methods vi.escaped = true; count--; } } if (Type.getReturnType(m.getSignature()) == Type.VOID || location instanceof ExceptionLocation) { return false; } InstructionHandle nextHandle = location.getHandle().getNext(); if (nextHandle == null || (nextHandle.getInstruction() instanceof POP || nextHandle.getInstruction() instanceof POP2)) { return false; } return propagateValues(vals, null, location.frameAfter().getTopValue()); }
@Override public void visit(Code obj) { uselessVoidCandidate = !classInit && !constructor && !getXMethod().isSynthetic() && Type.getReturnType(getMethodSig()) == Type.VOID; byte[] code = obj.getCode(); if(code.length == 4 && (code[0] & 0xFF) == Const.GETSTATIC && (code[3] & 0xFF) == Const.ARETURN) {
Type callReturnType = Type.getReturnType(callSeen.getMethodDescriptor().getSignature()); Type methodReturnType = Type.getReturnType(getMethodSig()); if(callReturnType.equals(methodReturnType) && callReturnType != Type.BOOLEAN && callReturnType != Type.VOID) { priority = HIGH_PRIORITY;
/** @return return type of referenced method. */ public Type getReturnType( final ConstantPoolGen cpg ) { return Type.getReturnType(getSignature(cpg)); }
/** * @return return type of method */ public Type getReturnType() { return Type.getReturnType(getSignature()); }
/** * @return type of field */ public Type getType() { return Type.getReturnType(getSignature()); } }
/** @return return type of referenced method. */ public Type getReturnType(ConstantPoolGen cpg) { return Type.getReturnType(getSignature(cpg)); }
/** * @return type of field */ public Type getType() { return Type.getReturnType(getSignature()); }
/** * @return return type of method */ public Type getReturnType() { return Type.getReturnType(getSignature()); }
/** * @param methodDescriptor */ private void sawNoSideEffectCall(MethodDescriptor methodDescriptor) { if(uselessVoidCandidate && Type.getReturnType(methodDescriptor.getSignature()) == Type.VOID && !methodDescriptor.getName().equals("<init>")) { /* To reduce false-positives we do not mark method as useless void if it calls * another useless void method. If that another method also in the scope of our project * then we will report it instead. If there's a cycle of no-side-effect calls, then * it's probably some delegation pattern and methods can be extended in future/derived * projects to do something useful. */ uselessVoidCandidate = false; } }
public static MethodBinding lookup(String className, String name, String signature) { String key= className + "#" + name + signature; MethodBinding binding= methodBindingsByKey.get(key); if (binding != null) return binding; binding= new MethodBinding(); binding.declaringClass= new ObjectType(className); binding.name= name; binding.parameterTypes= Type.getArgumentTypes(signature); binding.returnType= Type.getReturnType(signature); binding.signature= signature; methodBindingsByKey.put(key, binding); return binding; }
static InstructionHandle emitInvoke(InstructionList il, InstructionFactory fac, MethodRef method) { String signature = method.getSignature(); Type[] args = Type.getArgumentTypes(signature); Type ret = Type.getReturnType(signature); String mname = method.getName(); String cname = method.getDeclaringClass().getName(); short kind; if (method.getDeclaringClass().isInterface()) { kind = Constants.INVOKEINTERFACE; } else if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) { kind = Constants.INVOKESTATIC; } else if (method.getName().charAt(0) == '<') { kind = Constants.INVOKESPECIAL; } else { kind = Constants.INVOKEVIRTUAL; } return il.append(fac.createInvoke(cname, mname, ret, args, kind)); }
/** * Looks for the method referenced by the given invoke instruction in the given class. * @param jc the class that defines the referenced method * @param invoke the instruction that references the method * @return the referenced method or null if not found. */ private Method getMethod(final JavaClass jc, final InvokeInstruction invoke) { final Method[] ms = jc.getMethods(); for (final Method element : ms) { if ( (element.getName().equals(invoke.getMethodName(cpg))) && (Type.getReturnType(element.getSignature()).equals(invoke.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(element.getSignature()), invoke.getArgumentTypes(cpg))) ) { return element; } } return null; }
boolean propagateToReturnValue(Set<ValueInfo> vals, ValueNumber vn, GenLocation location, MethodDescriptor m) throws DataflowAnalysisException { for(ValueInfo vi : vals) { if(vi.type.getSignature().startsWith("[") && vi.hasObjectOnlyCall && vi.var == null && vn.getNumber() == vi.origValue) { // Ignore initialized arrays passed to methods vi.escaped = true; count--; } } if (Type.getReturnType(m.getSignature()) == Type.VOID || location instanceof ExceptionLocation) { return false; } InstructionHandle nextHandle = location.getHandle().getNext(); if (nextHandle == null || (nextHandle.getInstruction() instanceof POP || nextHandle.getInstruction() instanceof POP2)) { return false; } return propagateValues(vals, null, location.frameAfter().getTopValue()); }
/** Checks if the constraints of operands of the said instruction(s) are satisfied. */ public void visitINVOKESTATIC(INVOKESTATIC o){ // INVOKESTATIC is a LoadClass; the Class where the referenced method is declared in, // is therefore resolved/verified. // INVOKESTATIC is an InvokeInstruction, the argument and return types are resolved/verified, // too. So are the allowed method names. String classname = o.getClassName(cpg); JavaClass jc = Repository.lookupClass(classname); Method[] ms = jc.getMethods(); Method m = null; for (int i=0; i<ms.length; i++){ if ( (ms[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ m = ms[i]; break; } } if (m == null){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verifier possibly allows the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); } if (! (m.isStatic())){ // implies it's not abstract, verified in pass 2. constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' has ACC_STATIC unset."); } }
/** Checks if the constraints of operands of the said instruction(s) are satisfied. */ public void visitINVOKEVIRTUAL(INVOKEVIRTUAL o){ // INVOKEVIRTUAL is a LoadClass; the Class where the referenced method is declared in, // is therefore resolved/verified. // INVOKEVIRTUAL is an InvokeInstruction, the argument and return types are resolved/verified, // too. So are the allowed method names. String classname = o.getClassName(cpg); JavaClass jc = Repository.lookupClass(classname); Method[] ms = jc.getMethods(); Method m = null; for (int i=0; i<ms.length; i++){ if ( (ms[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ m = ms[i]; break; } } if (m == null){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superclass or implemented interface, which the Java Virtual Machine Specification, Second Edition does not."); } if (! (jc.isClass())){ constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is an interface, but not a class as expected."); } }
/** Checks if the constraints of operands of the said instruction(s) are satisfied. */ public void visitINVOKEINTERFACE(INVOKEINTERFACE o){ // INVOKEINTERFACE is a LoadClass; the Class where the referenced method is declared in, // is therefore resolved/verified. // INVOKEINTERFACE is an InvokeInstruction, the argument and return types are resolved/verified, // too. So are the allowed method names. String classname = o.getClassName(cpg); JavaClass jc = Repository.lookupClass(classname); Method[] ms = jc.getMethods(); Method m = null; for (int i=0; i<ms.length; i++){ if ( (ms[i].getName().equals(o.getMethodName(cpg))) && (Type.getReturnType(ms[i].getSignature()).equals(o.getReturnType(cpg))) && (objarrayequals(Type.getArgumentTypes(ms[i].getSignature()), o.getArgumentTypes(cpg))) ){ m = ms[i]; break; } } if (m == null){ constraintViolated(o, "Referenced method '"+o.getMethodName(cpg)+"' with expected signature not found in class '"+jc.getClassName()+"'. The native verfier does allow the method to be declared in some superinterface, which the Java Virtual Machine Specification, Second Edition does not."); } if (jc.isClass()){ constraintViolated(o, "Referenced class '"+jc.getClassName()+"' is a class, but not an interface as expected."); } }
public void visitConstantMethodref(ConstantMethodref obj){ if (obj.getTag() != Constants.CONSTANT_Methodref){ throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!"); } int name_and_type_index = obj.getNameAndTypeIndex(); ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name if (!validClassMethodName(name)){ throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); } int class_index = obj.getClassIndex(); ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form if (! validClassName(className)){ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); } String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) try{ Type t = Type.getReturnType(sig); if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){ throw new ClassConstraintException("Instance initialization method must have VOID return type."); } } catch (ClassFormatError cfe){ // Well, BCEL sometimes is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); } }