private static Set<SymbolicValue> computedFrom(@Nullable SymbolicValue symbolicValue) { if (symbolicValue == null) { return Collections.emptySet(); } Set<SymbolicValue> result = new HashSet<>(); result.add(symbolicValue); symbolicValue.computedFrom().forEach(sv -> result.addAll(computedFrom(sv))); return result; }
public static Set<Flow> flow(ExplodedGraph.Node currentNode, @Nullable SymbolicValue currentVal, List<Class<? extends Constraint>> domains, @Nullable Symbol trackSymbol) { return flow(currentNode, setFromNullable(currentVal), c -> true, c -> false, domains, setFromNullable(trackSymbol), false); }
private void processUnclosedSymbolicValue(ExplodedGraph.Node node, SymbolicValue sv) { FlowComputation.flowWithoutExceptions(node, sv, OPEN::equals, RESOURCE_CONSTRAINT_DOMAIN).stream() .flatMap(Flow::firstFlowLocation) .filter(location -> location.syntaxNode.is(Tree.Kind.NEW_CLASS, Tree.Kind.METHOD_INVOCATION)) .forEach(this::reportIssue); }
public static Set<Flow> flow(ExplodedGraph.Node currentNode, Set<SymbolicValue> symbolicValues, Predicate<Constraint> addToFlow, Predicate<Constraint> terminateTraversal, List<Class<? extends Constraint>> domains, Set<Symbol> symbols) { return flow(currentNode, symbolicValues, addToFlow, terminateTraversal, domains, symbols, false); }
private static Set<Flow> flow(ExplodedGraph.Node currentNode, Set<SymbolicValue> symbolicValues, Predicate<Constraint> addToFlow, Predicate<Constraint> terminateTraversal, List<Class<? extends Constraint>> domains, Set<Symbol> symbols, boolean skipExceptionMessages) { Set<SymbolicValue> allSymbolicValues = symbolicValues.stream() .map(FlowComputation::computedFrom) .flatMap(Set::stream) .collect(Collectors.toSet()); PSet<Symbol> trackedSymbols = PCollections.emptySet(); for (Symbol symbol: symbols) { trackedSymbols = trackedSymbols.add(symbol); } if (symbols.isEmpty()) { for (SymbolicValue symbolicValue : symbolicValues) { for (Symbol symbol : symbolicValue.computedFromSymbols()) { trackedSymbols = trackedSymbols.add(symbol); } } } FlowComputation flowComputation = new FlowComputation(allSymbolicValues, addToFlow, terminateTraversal, domains, skipExceptionMessages); return flowComputation.run(currentNode, trackedSymbols); }
Flow passedArgumentsMessages = flowsForPassedArguments(argumentIndices, mit); Flow changingNameArgumentsMessages = flowsForArgumentsChangingName(argumentIndices, mit);
public static Flow flowsForPassedArguments(List<Integer> argumentIndices, MethodInvocationTree mit) { String methodName = mit.symbol().name(); Flow.Builder flowBuilder = Flow.builder(); argumentIndices.stream() .map(index -> getArgumentIdentifier(mit, index)) .filter(Objects::nonNull) .map(identifierTree -> new JavaFileScannerContext.Location(String.format("'%s' is passed to '%s()'.", identifierTree.name(), methodName), identifierTree)) .forEach(flowBuilder::add); return flowBuilder.build().reverse(); }
private static Flow flowsForArgumentsChangingName(ExceptionalCheckBasedYield yield, MethodInvocationTree mit) { return FlowComputation.flowsForArgumentsChangingName(Collections.singletonList(yield.parameterCausingExceptionIndex()), mit); } }
private Set<Flow> run(final ExplodedGraph.Node node, PSet<Symbol> trackedSymbols) { Set<Flow> flows = new HashSet<>(); Deque<ExecutionPath> workList = new ArrayDeque<>(); SameConstraints sameConstraints = new SameConstraints(node, trackedSymbols, domains); node.edges().stream().flatMap(e -> startPath(e, trackedSymbols, sameConstraints)).forEach(workList::push); int flowSteps = 0; Set<ExecutionPath> visited = new HashSet<>(workList); while (!workList.isEmpty()) { ExecutionPath path = workList.pop(); if (path.finished) { flows.add(path.flow); } else { path.lastEdge.parent.edges().stream() .filter(path::notVisited) .flatMap(path::addEdge) .forEach(ep -> { if(visited.add(ep)) { workList.push(ep); } }); } flowSteps++; if(flowSteps == MAX_FLOW_STEPS) { LOG.debug("Flow was not able to complete"); break; } } return flows; }
public static Set<Flow> flow(ExplodedGraph.Node currentNode, Set<SymbolicValue> symbolicValues, Predicate<Constraint> addToFlow, Predicate<Constraint> terminateTraversal, List<Class<? extends Constraint>> domains, Set<Symbol> symbols) { return flow(currentNode, symbolicValues, addToFlow, terminateTraversal, domains, symbols, false); }
private static Set<Flow> flow(ExplodedGraph.Node currentNode, Set<SymbolicValue> symbolicValues, Predicate<Constraint> addToFlow, Predicate<Constraint> terminateTraversal, List<Class<? extends Constraint>> domains, Set<Symbol> symbols, boolean skipExceptionMessages) { Set<SymbolicValue> allSymbolicValues = symbolicValues.stream() .map(FlowComputation::computedFrom) .flatMap(Set::stream) .collect(Collectors.toSet()); PSet<Symbol> trackedSymbols = PCollections.emptySet(); for (Symbol symbol: symbols) { trackedSymbols = trackedSymbols.add(symbol); } if (symbols.isEmpty()) { for (SymbolicValue symbolicValue : symbolicValues) { for (Symbol symbol : symbolicValue.computedFromSymbols()) { trackedSymbols = trackedSymbols.add(symbol); } } } FlowComputation flowComputation = new FlowComputation(allSymbolicValues, addToFlow, terminateTraversal, domains, skipExceptionMessages); return flowComputation.run(currentNode, trackedSymbols); }
Flow passedArgumentsMessages = flowsForPassedArguments(argumentIndices, mit); Flow changingNameArgumentsMessages = flowsForArgumentsChangingName(argumentIndices, mit);
public static Flow flowsForPassedArguments(List<Integer> argumentIndices, MethodInvocationTree mit) { String methodName = mit.symbol().name(); Flow.Builder flowBuilder = Flow.builder(); argumentIndices.stream() .map(index -> getArgumentIdentifier(mit, index)) .filter(Objects::nonNull) .map(identifierTree -> new JavaFileScannerContext.Location(String.format("'%s' is passed to '%s()'.", identifierTree.name(), methodName), identifierTree)) .forEach(flowBuilder::add); return flowBuilder.build().reverse(); }
private static Flow flowsForArgumentsChangingName(ExceptionalCheckBasedYield yield, MethodInvocationTree mit) { return FlowComputation.flowsForArgumentsChangingName(Collections.singletonList(yield.parameterCausingExceptionIndex()), mit); } }
private Set<Flow> run(final ExplodedGraph.Node node, PSet<Symbol> trackedSymbols) { Set<Flow> flows = new HashSet<>(); Deque<ExecutionPath> workList = new ArrayDeque<>(); SameConstraints sameConstraints = new SameConstraints(node, trackedSymbols, domains); node.edges().stream().flatMap(e -> startPath(e, trackedSymbols, sameConstraints)).forEach(workList::push); int flowSteps = 0; Set<ExecutionPath> visited = new HashSet<>(workList); while (!workList.isEmpty()) { ExecutionPath path = workList.pop(); if (path.finished) { flows.add(path.flow); } else { path.lastEdge.parent.edges().stream() .filter(path::notVisited) .flatMap(path::addEdge) .forEach(ep -> { if(visited.add(ep)) { workList.push(ep); } }); } flowSteps++; if(flowSteps == MAX_FLOW_STEPS) { LOG.debug("Flow was not able to complete"); break; } } return flows; }
public static Set<Flow> flowWithoutExceptions(ExplodedGraph.Node currentNode, @Nullable SymbolicValue currentVal, Predicate<Constraint> addToFlow, Predicate<Constraint> terminateTraversal, List<Class<? extends Constraint>> domains) { return flow(currentNode, setFromNullable(currentVal), addToFlow, terminateTraversal, domains, Collections.emptySet(), true); }
public Set<Flow> flows() { return FlowComputation.flow(node, newValue, Collections.emptyList(), fromSymbol); } }
private void processUnclosedSymbolicValue(ExplodedGraph.Node node, SymbolicValue sv) { List<Class<? extends Constraint>> domains = Lists.newArrayList(CustomResourceConstraint.class); FlowComputation.flowWithoutExceptions(node, sv, OPENED::equals, domains).stream() .flatMap(Flow::firstFlowLocation) .filter(location -> location.syntaxNode.is(Tree.Kind.NEW_CLASS, Tree.Kind.METHOD_INVOCATION)) .forEach(this::reportIssue); }
public static Flow flowsForArgumentsChangingName(List<Integer> argumentIndices, MethodInvocationTree mit) { JavaSymbol.MethodJavaSymbol methodSymbol = (JavaSymbol.MethodJavaSymbol) mit.symbol(); MethodTree declaration = methodSymbol.declaration(); if (declaration == null) { return Flow.empty(); } Flow.Builder flowBuilder = Flow.builder(); List<VariableTree> methodParameters = declaration.parameters(); for (Integer argumentIndex : argumentIndices) { // do not consider varargs part if (methodSymbol.isVarArgs() && argumentIndex >= methodParameters.size() - 1) { break; } IdentifierTree argumentName = getArgumentIdentifier(mit, argumentIndex); if (argumentName != null) { IdentifierTree parameterIdentifier = methodParameters.get(argumentIndex).simpleName(); String identifierName = parameterIdentifier.name(); if (!argumentName.name().equals(identifierName)) { flowBuilder.add(new JavaFileScannerContext.Location(String.format(IMPLIES_SAME_VALUE, identifierName, argumentName.name()), parameterIdentifier)); } } } return flowBuilder.build().reverse(); }
private static Set<SymbolicValue> computedFrom(@Nullable SymbolicValue symbolicValue) { if (symbolicValue == null) { return Collections.emptySet(); } Set<SymbolicValue> result = new HashSet<>(); result.add(symbolicValue); symbolicValue.computedFrom().forEach(sv -> result.addAll(computedFrom(sv))); return result; }