noSideEffectMethods.add(m, MethodSideEffectStatus.SE_CLINIT); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE_EX); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE_EX); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE); } else { // void methods if(uselessVoidCandidates.contains(m)) { noSideEffectMethods.add(m, MethodSideEffectStatus.USELESS); noSideEffectMethods.add(m, MethodSideEffectStatus.OBJ);
if (noSideEffectMethods.excluded(callSeen.getMethodDescriptor())) { sawExcludedNSECall = true; if (noSideEffectMethods.hasNoSideEffect(callSeen.getMethodDescriptor())) { int priority = NORMAL_PRIORITY; Type callReturnType = Type.getReturnType(callSeen.getMethodDescriptor().getSignature());
case Const.INVOKESPECIAL: case Const.INVOKEVIRTUAL: if(nse.is(getMethodDescriptorOperand(), MethodSideEffectStatus.OBJ, MethodSideEffectStatus.SE)) { checkStackValue(getNumberArguments(getMethodDescriptorOperand().getSignature()));
m = xMethod.getMethodDescriptor(); MethodSideEffectStatus status = noSideEffectMethods.status(m); if(status == MethodSideEffectStatus.NSE || status == MethodSideEffectStatus.SE_CLINIT) { if(m.getName().equals("<init>")) {
case INVOKESPECIAL: case INVOKEVIRTUAL: if(nse.is(getMethodDescriptorOperand(), MethodSideEffectStatus.OBJ, MethodSideEffectStatus.SE)) { checkStackValue(getNumberArguments(getMethodDescriptorOperand().getSignature()));
noSideEffectMethods.add(m, MethodSideEffectStatus.SE_CLINIT); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE_EX); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE_EX); continue; noSideEffectMethods.add(m, MethodSideEffectStatus.NSE); } else { // void methods if(uselessVoidCandidates.contains(m)) { noSideEffectMethods.add(m, MethodSideEffectStatus.USELESS); noSideEffectMethods.add(m, MethodSideEffectStatus.OBJ);
if (noSideEffectMethods.excluded(callSeen.getMethodDescriptor())) { sawExcludedNSECall = true; if (noSideEffectMethods.hasNoSideEffect(callSeen.getMethodDescriptor())) { int priority = NORMAL_PRIORITY; Type callReturnType = Type.getReturnType(callSeen.getMethodDescriptor().getSignature());
void initObservedValues() throws DataflowAnalysisException { for(Iterator<Location> iterator = cfg.locationIterator(); iterator.hasNext(); ) { Location location = iterator.next(); Instruction instruction = location.getHandle().getInstruction(); if(instruction instanceof ANEWARRAY || instruction instanceof NEWARRAY || instruction instanceof MULTIANEWARRAY) { int number = vna.getFactAfterLocation(location).getTopValue().getNumber(); TypeFrame typeFrame = ta.getFactAfterLocation(location); if(typeFrame.isValid()) { Type type = typeFrame.getTopValue(); observedValues.put(number, new ValueInfo(number, location, type)); } } else if(instruction instanceof INVOKESPECIAL) { InvokeInstruction inv = (InvokeInstruction) instruction; if (inv.getMethodName(cpg).equals("<init>") && noSideEffectMethods.hasNoSideEffect(new MethodDescriptor(inv, cpg))) { int number = vna.getFactAtLocation(location).getStackValue(inv.consumeStack(cpg)-1).getNumber(); TypeFrame typeFrame = ta.getFactAtLocation(location); if(typeFrame.isValid()) { Type type = typeFrame.getStackValue(inv.consumeStack(cpg)-1); observedValues.put(number, new ValueInfo(number, location, type)); } } } } thisValue = vna.getThisValue(); if(thisValue != null) { observedValues.remove(thisValue.getNumber()); } count = observedValues.size(); }
private void killLoadsOfObjectsPassed(InvokeInstruction ins) { try { XMethod called = Hierarchy2.findExactMethod(ins, methodGen.getConstantPool(), Hierarchy.ANY_METHOD); if (called != null ) { NoSideEffectMethodsDatabase nse = Global.getAnalysisCache().getOptionalDatabase(NoSideEffectMethodsDatabase.class); if(nse != null && !nse.is(called.getMethodDescriptor(), MethodSideEffectStatus.SE, MethodSideEffectStatus.OBJ)) { return; } } FieldSummary fieldSummary = AnalysisContext.currentAnalysisContext().getFieldSummary(); Set<XField> touched = fieldSummary.getFieldsWritten(called); if (!touched.isEmpty()) { getFrame().killLoadsOf(touched); } int passed = getNumWordsConsumed(ins); ValueNumber[] arguments = allocateValueNumberArray(passed); getFrame().killLoadsWithSimilarName(ins.getClassName(cpg), ins.getMethodName(cpg)); getFrame().getTopStackWords(arguments); for (ValueNumber v : arguments) { getFrame().killAllLoadsOf(v); } // Too many false-positives for primitives without transitive FieldSummary analysis, // so currently we simply kill any writable primitive on any method call // TODO: implement transitive FieldSummary getFrame().killAllLoads(true); } catch (DataflowAnalysisException e) { AnalysisContext.logError("Error in killLoadsOfObjectsPassed", e); } }
public boolean useless(MethodDescriptor m) { return status(m) == MethodSideEffectStatus.USELESS; }
public boolean hasNoSideEffect(MethodDescriptor m) { return status(m) == MethodSideEffectStatus.NSE; }
public boolean excluded(MethodDescriptor m) { return is(m, MethodSideEffectStatus.NSE_EX, MethodSideEffectStatus.SE_CLINIT); } }
/** * @param m method to check * @param statuses allowed statuses * @return true if method status is one of the statuses */ public boolean is(MethodDescriptor m, MethodSideEffectStatus... statuses) { MethodSideEffectStatus s = status(m); for(MethodSideEffectStatus status : statuses) { if(s == status) { return true; } } return false; }
private boolean hasSideEffect(int seen) { if(seen == INVOKEVIRTUAL || seen == INVOKESPECIAL || seen == INVOKEINTERFACE || seen == INVOKESTATIC) { return noSideEffectMethods.is(getMethodDescriptorOperand(), MethodSideEffectStatus.SE, MethodSideEffectStatus.OBJ); } return isRegisterStore() || isReturn(seen) || isSwitch(seen) || seen == INVOKEDYNAMIC || seen == PUTFIELD || seen == PUTSTATIC; }
@Override public void visitAfter(Code code) { if(bugAccumulator.getLastBugLocation() == null && !sawExcludedNSECall && noSideEffectMethods.useless(getMethodDescriptor())) { // Do not report UC_USELESS_VOID_METHOD if something was already reported inside the current method // it's likely that UC_USELESS_VOID_METHOD is just the consequence of the previous report bugAccumulator.accumulateBug(new BugInstance(this, "UC_USELESS_VOID_METHOD", code.getCode().length > 40 ? HIGH_PRIORITY : code.getCode().length > 15 ? NORMAL_PRIORITY : LOW_PRIORITY) .addClassAndMethod(getMethodDescriptor()), this); } sawExcludedNSECall = false; bugAccumulator.reportAccumulatedBugs(); }
m = xMethod.getMethodDescriptor(); MethodSideEffectStatus status = noSideEffectMethods.status(m); if(status == MethodSideEffectStatus.NSE || status == MethodSideEffectStatus.SE_CLINIT) { if(m.getName().equals(CONSTRUCTOR_NAME)) {
void initObservedValues() throws DataflowAnalysisException { for(Iterator<Location> iterator = cfg.locationIterator(); iterator.hasNext(); ) { Location location = iterator.next(); Instruction instruction = location.getHandle().getInstruction(); if(instruction instanceof ANEWARRAY || instruction instanceof NEWARRAY || instruction instanceof MULTIANEWARRAY) { int number = vna.getFactAfterLocation(location).getTopValue().getNumber(); TypeFrame typeFrame = ta.getFactAfterLocation(location); if(typeFrame.isValid()) { Type type = typeFrame.getTopValue(); observedValues.put(number, new ValueInfo(number, location, type)); } } else if(instruction instanceof INVOKESPECIAL) { InvokeInstruction inv = (InvokeInstruction) instruction; if (inv.getMethodName(cpg).equals(CONSTRUCTOR_NAME) && noSideEffectMethods.hasNoSideEffect(new MethodDescriptor(inv, cpg))) { int number = vna.getFactAtLocation(location).getStackValue(inv.consumeStack(cpg)-1).getNumber(); TypeFrame typeFrame = ta.getFactAtLocation(location); if(typeFrame.isValid()) { Type type = typeFrame.getStackValue(inv.consumeStack(cpg)-1); observedValues.put(number, new ValueInfo(number, location, type)); } } } } thisValue = vna.getThisValue(); if(thisValue != null) { observedValues.remove(thisValue.getNumber()); } count = observedValues.size(); }
private void killLoadsOfObjectsPassed(InvokeInstruction ins) { try { XMethod called = Hierarchy2.findExactMethod(ins, methodGen.getConstantPool(), Hierarchy.ANY_METHOD); if (called != null ) { NoSideEffectMethodsDatabase nse = Global.getAnalysisCache().getOptionalDatabase(NoSideEffectMethodsDatabase.class); if(nse != null && !nse.is(called.getMethodDescriptor(), MethodSideEffectStatus.SE, MethodSideEffectStatus.OBJ)) { return; } } FieldSummary fieldSummary = AnalysisContext.currentAnalysisContext().getFieldSummary(); Set<XField> touched = fieldSummary.getFieldsWritten(called); if (!touched.isEmpty()) { getFrame().killLoadsOf(touched); } int passed = getNumWordsConsumed(ins); ValueNumber[] arguments = allocateValueNumberArray(passed); getFrame().killLoadsWithSimilarName(ins.getClassName(cpg), ins.getMethodName(cpg)); getFrame().getTopStackWords(arguments); for (ValueNumber v : arguments) { getFrame().killAllLoadsOf(v); } // Too many false-positives for primitives without transitive FieldSummary analysis, // so currently we simply kill any writable primitive on any method call // TODO: implement transitive FieldSummary getFrame().killAllLoads(true); } catch (DataflowAnalysisException e) { AnalysisContext.logError("Error in killLoadsOfObjectsPassed", e); } }
public boolean hasNoSideEffect(MethodDescriptor m) { return status(m) == MethodSideEffectStatus.NSE; }
/** * @param m method to check * @param statuses allowed statuses * @return true if method status is one of the statuses */ public boolean is(MethodDescriptor m, MethodSideEffectStatus... statuses) { MethodSideEffectStatus s = status(m); for(MethodSideEffectStatus status : statuses) { if(s == status) { return true; } } return false; }