/** * Determine whether given backwards FlowValue conflicts with given source. * * @param backwardsFlowValue * a backwards FlowValue * @param source * SourceSinkInfo object representing a source reached by the * backwards flow value * @param typeQualifierValue * TypeQualifierValue being checked * @param isIdentity TODO * @return true if backwards value conflicts with source, false if not */ public static boolean backwardsValueConflictsWithSource(FlowValue backwardsFlowValue, SourceSinkInfo source, TypeQualifierValue typeQualifierValue, boolean isIdentity) { When sourceWhen = source.getWhen(); if (typeQualifierValue.isStrictQualifier() && !isIdentity) { // strict checking return (backwardsFlowValue == ALWAYS && sourceWhen != When.ALWAYS) || (backwardsFlowValue == NEVER && sourceWhen != When.NEVER); } else { // NOT strict checking return (backwardsFlowValue == ALWAYS && (sourceWhen == When.NEVER || sourceWhen == When.MAYBE)) || (backwardsFlowValue == NEVER && (sourceWhen == When.ALWAYS || sourceWhen == When.MAYBE)); } }
private void registerParameterSources() { ValueNumberFrame vnaFrameAtEntry = vnaDataflow.getStartFact(cfg.getEntry()); SignatureParser sigParser = new SignatureParser(xmethod.getSignature()); int firstParamSlot = xmethod.isStatic() ? 0 : 1; int param = 0; int slotOffset = 0; for (Iterator<String> i = sigParser.parameterSignatureIterator(); i.hasNext();) { String paramSig = i.next(); // Get the TypeQualifierAnnotation for this parameter SourceSinkInfo info; TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(xmethod, param, typeQualifierValue); When when = (tqa != null) ? tqa.when : When.UNKNOWN; ValueNumber vn = vnaFrameAtEntry.getValue(slotOffset + firstParamSlot); info = new SourceSinkInfo(SourceSinkType.PARAMETER, cfg.getLocationAtEntry(), vn, when); info.setParameterAndLocal(param, slotOffset + firstParamSlot); registerSourceSink(info); param++; slotOffset += SignatureParser.getNumSlotsForType(paramSig); } }
private void modelFieldStore(Location location) throws DataflowAnalysisException { // Model field stores XField writtenField = XFactory.createXField((FieldInstruction) location.getHandle().getInstruction(), cpg); TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(writtenField, typeQualifierValue); When when = (tqa != null) ? tqa.when : When.UNKNOWN; // The ValueNumberFrame *before* the FieldInstruction should // have the ValueNumber of the stored value on the top of the stack. ValueNumberFrame vnaFrameAtStore = vnaDataflow.getFactAtLocation(location); if (vnaFrameAtStore.isValid()) { ValueNumber vn = vnaFrameAtStore.getTopValue(); SourceSinkInfo sink = new SourceSinkInfo(SourceSinkType.FIELD_STORE, location, vn, when); registerSourceSink(sink); } }
public When validate(Object constantValue) { if (validator == null) throw new IllegalStateException("No validator"); IAnalysisCache analysisCache = Global.getAnalysisCache(); Profiler profiler = analysisCache.getProfiler(); profiler.start(validator.getClass()); AtomicBoolean performing = performingValidation.get(); try { if (!performing.compareAndSet(false, true)) { throw new IllegalStateException("recursive validation"); } return validator.forConstantValue(proxy, constantValue); } catch (Exception e) { AnalysisContext.logError("Error executing custom validator for " + typeQualifier + " " + constantValue, e); return When.UNKNOWN; } finally { if (!performing.compareAndSet(true, false)) { throw new IllegalStateException("performingValidation not set when validation completes"); } profiler.end(validator.getClass()); } }
private static TypeQualifierAnnotation combineAnnotations(TypeQualifierAnnotation a, TypeQualifierAnnotation b, When[][] mergeMatrix) { assert a.typeQualifier.equals(b.typeQualifier); When aWhen = a.when; When bWhen = b.when; if (aWhen.ordinal() < bWhen.ordinal()) { When tmp = aWhen; aWhen = bWhen; bWhen = tmp; } When combined = mergeMatrix[aWhen.ordinal()][bWhen.ordinal()]; if (combined != null) { return getValue(a.typeQualifier, combined); } else { return null; } }
public boolean parameterMustBeNonNull(XMethod m, int param) { if (DEBUG) { System.out.print("Checking " + m + " param " + param + " for @Nonnull..."); } TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(m, param, nonnullTypeQualifierValue); if (tqa == null && param == 0) { String name = m.getName(); String signature = m.getSignature(); if (name.equals("main") && signature.equals("([Ljava/lang/String;)V") && m.isStatic() && m.isPublic()) return true; else if (NullnessAnnotationDatabase.assertsFirstParameterIsNonnull(m)) return true; else if (name.equals("compareTo") && signature.substring(signature.indexOf(";") + 1).equals(")Z") && !m.isStatic()) return true; } boolean answer = (tqa != null) && tqa.when == When.ALWAYS; if (DEBUG) { System.out.println(answer ? "yes" : "no"); } return answer; }
private void registerParameterSources() { ValueNumberFrame vnaFrameAtEntry = vnaDataflow.getStartFact(cfg.getEntry()); SignatureParser sigParser = new SignatureParser(xmethod.getSignature()); int firstParamSlot = xmethod.isStatic() ? 0 : 1; int param = 0; int slotOffset = 0; for ( String paramSig : sigParser.parameterSignatures()) { // Get the TypeQualifierAnnotation for this parameter SourceSinkInfo info; TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(xmethod, param, typeQualifierValue); When when = (tqa != null) ? tqa.when : When.UNKNOWN; ValueNumber vn = vnaFrameAtEntry.getValue(slotOffset + firstParamSlot); info = new SourceSinkInfo(SourceSinkType.PARAMETER, cfg.getLocationAtEntry(), vn, when); info.setParameterAndLocal(param, slotOffset + firstParamSlot); registerSourceSink(info); param++; slotOffset += SignatureParser.getNumSlotsForType(paramSig); } }
public boolean parameterMustBeNonNull(XMethod m, int param) { if (DEBUG) { System.out.print("Checking " + m + " param " + param + " for @Nonnull..."); } TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(m, param, nonnullTypeQualifierValue); if (tqa == null && param == 0) { String name = m.getName(); String signature = m.getSignature(); if (name.equals("main") && signature.equals("([Ljava/lang/String;)V") && m.isStatic() && m.isPublic()) return true; else if (assertsFirstParameterIsNonnull(m)) return true; else if (name.equals("compareTo") && signature.substring(signature.indexOf(";") + 1).equals(")Z") && !m.isStatic()) return true; } boolean answer = (tqa != null) && tqa.when == When.ALWAYS; if (DEBUG) { System.out.println(answer ? "yes" : "no"); } return answer; }
/** * Java options. * @return Options */ private Collection<String> options() { final Collection<String> opts = new LinkedList<>(); opts.add("-classpath"); opts.add( StringUtils.join( Arrays.asList( this.jar(Wrap.class), this.jar(FindBugs2.class), this.jar(ClassFormatException.class), this.jar(DocumentException.class), this.jar(JaxenException.class), this.jar(ClassNode.class), this.jar(ClassVisitor.class), this.jar(When.class), this.jar(FormatterNumberFormatException.class), this.jar(StringEscapeUtils.class), this.jar(FBContrib.class), this.jar(Iterables.class) ), // @checkstyle MultipleStringLiteralsCheck (1 line) System.getProperty("path.separator") ).replace("\\", "/") ); return opts; }
@Nonnull( when = When.ALWAYS ) public static <T> T requireNonNull( T object ) throws NullPointerException { if ( object == null ) { throw new NullPointerException(); } return object; }
public void visitClassContext(ClassContext classContext) { JavaClass jclass = classContext.getJavaClass(); for (Method method : jclass.getMethods()) { XMethod xmethod = XFactory.createXMethod(classContext.getJavaClass(), method); ParameterProperty nonnullParameters = AnalysisContext.currentAnalysisContext().getUnconditionalDerefParamDatabase() .getProperty(xmethod.getMethodDescriptor()); if (nonnullParameters != null) { for (int p : nonnullParameters.iterable()) { TypeQualifierAnnotation directTypeQualifierAnnotation = TypeQualifierApplications .getDirectTypeQualifierAnnotation(xmethod, p, nonnullTypeQualifierValue); if (directTypeQualifierAnnotation != null && directTypeQualifierAnnotation.when == When.UNKNOWN) { // // The LocalVariableAnnotation is constructed using the // local variable // number of the parameter, not the parameter number. // int paramLocal = xmethod.isStatic() ? p : p + 1; reporter.reportBug(new BugInstance(this, "NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE", NORMAL_PRIORITY).addClassAndMethod(jclass, method).add( LocalVariableAnnotation.getParameterLocalVariableAnnotation(method, paramLocal))); } } } } }
/** * Convert a When value to a FlowValue value. * * @param when * a When value * @return the corresponding FlowValue */ public static FlowValue flowValueFromWhen(When when) { switch (when) { case ALWAYS: return FlowValue.ALWAYS; case MAYBE: return FlowValue.UNKNOWN; case NEVER: return FlowValue.NEVER; case UNKNOWN: return FlowValue.UNKNOWN; default: throw new IllegalStateException(); } }
private void registerConstantSource(Location location, Object constantValue) throws DataflowAnalysisException { When w; if (typeQualifierValue.canValidate(constantValue)) { w = typeQualifierValue.validate(constantValue); } else if (typeQualifierValue.isStrictQualifier()) return; else w = When.UNKNOWN; registerTopOfStackSource(SourceSinkType.CONSTANT_VALUE, location, w, false, constantValue); }
private void registerReturnValueSource(Location location) throws DataflowAnalysisException { // Nothing to do if called method does not return a value InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction(); String calledMethodSig = inv.getSignature(cpg); if (calledMethodSig.endsWith(")V")) { return; } XMethod calledXMethod = XFactory.createXMethod(inv, cpg); if (TypeQualifierDataflowAnalysis.isIdentifyFunctionForTypeQualifiers(calledXMethod)) return; if (calledXMethod.isResolved()) { TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(calledXMethod, typeQualifierValue); boolean interproc = false; if (TypeQualifierDatabase.USE_DATABASE && tqa == null) { // See if there's an entry in the interprocedural // type qualifier database. TypeQualifierDatabase tqdb = Global.getAnalysisCache().getDatabase(TypeQualifierDatabase.class); tqa = tqdb.getReturnValue(calledXMethod.getMethodDescriptor(), typeQualifierValue); if (tqa != null) { interproc = true; } } When when = (tqa != null) ? tqa.when : When.UNKNOWN; registerTopOfStackSource(SourceSinkType.RETURN_VALUE_OF_CALLED_METHOD, location, when, interproc, null); } }
private void registerFieldLoadSource(Location location) throws DataflowAnalysisException { XField loadedField = XFactory.createXField((FieldInstruction) location.getHandle().getInstruction(), cpg); if (loadedField.isResolved()) { TypeQualifierAnnotation tqa = TypeQualifierApplications.getEffectiveTypeQualifierAnnotation(loadedField, typeQualifierValue); When when = (tqa != null) ? tqa.when : When.UNKNOWN; registerTopOfStackSource(SourceSinkType.FIELD_LOAD, location, when, false, null); } }
private void registerTopOfStackSource(SourceSinkType sourceSinkType, Location location, When when, boolean interproc, Object constantValue) throws DataflowAnalysisException { if (when == When.UNKNOWN && !typeQualifierValue.isStrictQualifier()) return; ValueNumberFrame vnaFrameAfterInstruction = vnaDataflow.getFactAfterLocation(location); if (vnaFrameAfterInstruction.isValid()) { ValueNumber tosValue = vnaFrameAfterInstruction.getTopValue(); SourceSinkInfo sourceSinkInfo = new SourceSinkInfo(sourceSinkType, location, tosValue, when); sourceSinkInfo.setInterproc(interproc); sourceSinkInfo.setConstantValue(constantValue); registerSourceSink(sourceSinkInfo); } }
private void modelReturn(TypeQualifierAnnotation returnValueAnnotation, Location location) throws DataflowAnalysisException { When when = (returnValueAnnotation != null) ? returnValueAnnotation.when : When.UNKNOWN; // Model return statement ValueNumberFrame vnaFrameAtReturn = vnaDataflow.getFactAtLocation(location); if (vnaFrameAtReturn.isValid()) { ValueNumber topValue = vnaFrameAtReturn.getTopValue(); SourceSinkInfo sink = new SourceSinkInfo(SourceSinkType.RETURN_VALUE, location, topValue, when); registerSourceSink(sink); } }
/** * @param result * @param applicableApplications */ public static void addKnownTypeQualifiers(HashSet<TypeQualifierValue<?>> result, Collection<TypeQualifierAnnotation> applicableApplications) { for (TypeQualifierAnnotation t : applicableApplications) { if (t.when != When.UNKNOWN) { result.add(t.typeQualifier); } } }
public static @Nonnull Collection<TypeQualifierAnnotation> getValues(Map<TypeQualifierValue, When> map) { Collection<TypeQualifierAnnotation> result = new LinkedList<TypeQualifierAnnotation>(); for (Map.Entry<TypeQualifierValue, When> e : map.entrySet()) { result.add(getValue(e.getKey(), e.getValue())); } return result; }
public static @Nonnull TypeQualifierAnnotation getValue(TypeQualifierValue desc, When when) { DualKeyHashMap<TypeQualifierValue, When, TypeQualifierAnnotation> map = instance.get(); TypeQualifierAnnotation result = map.get(desc, when); if (result != null) return result; result = new TypeQualifierAnnotation(desc, when); map.put(desc, when, result); return result; }
@CheckReturnValue(when = When.NEVER) public int checkLimit(final int limit) { if (limit > capacity) { throw new IndexOutOfBoundsException(String.format("limit is beyond capacity (l=%d; c=%d)" , limit, capacity)); } return limit; }
@CheckReturnValue(when = When.NEVER) int checkIndex(final int index) { if (index >= capacity) { throw new IndexOutOfBoundsException(String.format("index is beyond bound (i=%d; b=%d)" , index, capacity - 1)); } return index; }
private void registerConstantSource(Location location, @CheckForNull Object constantValue) throws DataflowAnalysisException { When w; if (typeQualifierValue.canValidate(constantValue)) { w = typeQualifierValue.validate(constantValue); } else if (typeQualifierValue.isStrictQualifier()) return; else w = When.UNKNOWN; registerTopOfStackSource(SourceSinkType.CONSTANT_VALUE, location, w, false, constantValue); }
private void registerTopOfStackSource(SourceSinkType sourceSinkType, Location location, When when, boolean interproc, @CheckForNull Object constantValue) throws DataflowAnalysisException { if (when == When.UNKNOWN && !typeQualifierValue.isStrictQualifier()) return; ValueNumberFrame vnaFrameAfterInstruction = vnaDataflow.getFactAfterLocation(location); if (vnaFrameAfterInstruction.isValid()) { ValueNumber tosValue = vnaFrameAfterInstruction.getTopValue(); SourceSinkInfo sourceSinkInfo = new SourceSinkInfo(sourceSinkType, location, tosValue, when); sourceSinkInfo.setInterproc(interproc); sourceSinkInfo.setConstantValue(constantValue); registerSourceSink(sourceSinkInfo); } }
public static <A extends Annotation> When sandboxedValidation(A proxy, TypeQualifierValidator<A> v, @CheckForNull Object constantValue) { if (performingValidation.get()) throw new IllegalStateException("recursive validation"); try { performingValidation.set(Boolean.TRUE); if (TypeQualifierValue.DEBUG_CLASSLOADING) System.out.println("Performing validation in thread " + Thread.currentThread().getName()); try { When result = v.forConstantValue(proxy, constantValue); if (!performingValidation.get()) throw new IllegalStateException("performingValidation not set when validation completes"); return result; } catch (ClassCastException e) { Class<? extends Annotation> c = proxy.getClass(); System.out.println(c.getName() + " extends " + c.getSuperclass().getName()); for(Class<?> i : c.getInterfaces()) System.out.println(" " + i.getName()); throw e; } } finally { performingValidation.set(Boolean.FALSE); if (TypeQualifierValue.DEBUG_CLASSLOADING) System.out.println("Validation finished in thread " + Thread.currentThread().getName()); } }
/** * @param result * @param applicableApplications */ public static void addKnownTypeQualifiers(HashSet<? super TypeQualifierValue<?>> result, Collection<TypeQualifierAnnotation> applicableApplications) { for (TypeQualifierAnnotation t : applicableApplications) { if (t.when != When.UNKNOWN) { result.add(t.typeQualifier); } } }
public When validate(@CheckForNull Object constantValue) { if (validator == null) throw new IllegalStateException("No validator"); IAnalysisCache analysisCache = Global.getAnalysisCache(); Profiler profiler = analysisCache.getProfiler(); profiler.start(validator.getClass()); try { return ValidationSecurityManager.sandboxedValidation(proxy, validator, constantValue); } catch (Exception e) { AnalysisContext.logError("Error executing custom validator for " + typeQualifier + " " + constantValue, e); return When.UNKNOWN; } finally { profiler.end(validator.getClass()); } }
public static @Nonnull Collection<TypeQualifierAnnotation> getValues(Map<TypeQualifierValue<?>, When> map) { Collection<TypeQualifierAnnotation> result = new LinkedList<TypeQualifierAnnotation>(); for (Map.Entry<TypeQualifierValue<?>, When> e : map.entrySet()) { result.add(getValue(e.getKey(), e.getValue())); } return result; }
public static @Nonnull TypeQualifierAnnotation getValue(TypeQualifierValue<?> desc, When when) { DualKeyHashMap<TypeQualifierValue<?>, When, TypeQualifierAnnotation> map = instance.get(); TypeQualifierAnnotation result = map.get(desc, when); if (result != null) return result; result = new TypeQualifierAnnotation(desc, when); map.put(desc, when, result); return result; }
/** * {@inheritDoc} */ @Override public int compare(@Nonnull(when = When.MAYBE) final SelectionKey o1, @Nonnull(when = When.MAYBE) final SelectionKey o2) { if ((o1 == o2) || (o1 == null && o2 == null)) { return 0; } if (o1 == null) { return -1; } if (o2 == null) { return 1; } return Integer.signum(o2.hashCode() - o1.hashCode()); }
/** * Creates an iterator that will follow the leading sequences. * * @param buffer * @param leading */ private RingBufferIterator(@Nonnull final RingBuffer<E> buffer, @Nonnull(when = When.MAYBE) final Sequence... leading) { if (buffer == null) { throw new NullPointerException("buffer == null"); } this.buffer = buffer; this.leading = leading; this.closed = false; }
public void foo3(@SlashedClassName(when=When.UNKNOWN) String c) { foo(c); }