/** * Returns node associated with given (programPoint,programState) pair. If no node for this pair exists, it is created. */ public Node node(ProgramPoint programPoint, @Nullable ProgramState programState) { Node result = new Node(programPoint, programState, this); Node cached = nodes.get(result); if (cached != null) { cached.isNew = false; return cached; } result.isNew = true; nodes.put(result, result); nodesByProgramPoint.put(programPoint, result); return result; }
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 void enqueue(ProgramPoint newProgramPoint, ProgramState programState, boolean exitPath, @Nullable MethodYield methodYield) { ProgramPoint programPoint = newProgramPoint; int nbOfExecution = programState.numberOfTimeVisited(programPoint); if (nbOfExecution > MAX_EXEC_PROGRAM_POINT) { if (isRestartingForEachLoop(programPoint)) { // reached the max number of visit by program point, so take the false branch with current program state programPoint = new ProgramPoint(((CFG.Block) programPoint.block).falseBlock()); } else { debugPrint(programPoint); return; } } checkExplodedGraphTooBig(programState); ProgramState ps = programState.visitedPoint(programPoint, nbOfExecution + 1); ExplodedGraph.Node cachedNode = explodedGraph.node(programPoint, ps); if (!cachedNode.isNew() && exitPath == cachedNode.exitPath) { // has been enqueued earlier cachedNode.addParent(node, methodYield); return; } cachedNode.exitPath = exitPath; cachedNode.addParent(node, methodYield); workList.addFirst(cachedNode); }
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; }
private static boolean sameConstraintWhenSameProgramPoint(ExplodedGraph.Node currentNode, Symbol symbol, Class<? extends Constraint> domain) { ProgramState programState = currentNode.programState; SymbolicValue sv = programState.getValue(symbol); if (sv == null) { return false; } Constraint constraint = programState.getConstraint(sv, domain); if (constraint == null) { return false; } Collection<Node> siblingNodes = currentNode.siblings(); return siblingNodes.stream() .map(node -> node.programState) .allMatch(ps -> { SymbolicValue siblingSV = ps.getValue(symbol); if (siblingSV == null) { return false; } Constraint siblingConstraint = ps.getConstraint(siblingSV, domain); return constraint.equals(siblingConstraint); }); }
public void enqueue(ProgramPoint newProgramPoint, ProgramState programState, boolean exitPath, @Nullable MethodYield methodYield) { ProgramPoint programPoint = newProgramPoint; int nbOfExecution = programState.numberOfTimeVisited(programPoint); if (nbOfExecution > MAX_EXEC_PROGRAM_POINT) { if (isRestartingForEachLoop(programPoint)) { // reached the max number of visit by program point, so take the false branch with current program state programPoint = new ProgramPoint(((CFG.Block) programPoint.block).falseBlock()); } else { debugPrint(programPoint); return; } } checkExplodedGraphTooBig(programState); ProgramState ps = programState.visitedPoint(programPoint, nbOfExecution + 1); ExplodedGraph.Node cachedNode = explodedGraph.node(programPoint, ps); if (!cachedNode.isNew() && exitPath == cachedNode.exitPath) { // has been enqueued earlier cachedNode.addParent(node, methodYield); return; } cachedNode.exitPath = exitPath; cachedNode.addParent(node, methodYield); workList.addFirst(cachedNode); }
private Flow flowForNullableMethodParameters(ExplodedGraph.Node node) { if (!node.edges().isEmpty() || !domains.contains(ObjectConstraint.class)) { return Flow.empty(); } Flow.Builder flowBuilder = Flow.builder(); trackedSymbols.forEach(symbol -> { SymbolicValue sv = node.programState.getValue(symbol); if (sv == null) { return; } ObjectConstraint startConstraint = node.programState.getConstraint(sv, ObjectConstraint.class); if (startConstraint != null && isMethodParameter(symbol)) { String msg = IMPLIES_CAN_BE_MSG; if (ObjectConstraint.NOT_NULL == startConstraint) { msg = "Implies '%s' can not be %s."; } flowBuilder.add(new JavaFileScannerContext.Location(String.format(msg, symbol.name(), "null"), ((VariableTree) symbol.declaration()).simpleName())); } }); return flowBuilder.build(); }
private static boolean sameConstraintWhenSameProgramPoint(ExplodedGraph.Node currentNode, Symbol symbol, Class<? extends Constraint> domain) { ProgramState programState = currentNode.programState; SymbolicValue sv = programState.getValue(symbol); if (sv == null) { return false; } Constraint constraint = programState.getConstraint(sv, domain); if (constraint == null) { return false; } Collection<Node> siblingNodes = currentNode.siblings(); return siblingNodes.stream() .map(node -> node.programState) .allMatch(ps -> { SymbolicValue siblingSV = ps.getValue(symbol); if (siblingSV == null) { return false; } Constraint siblingConstraint = ps.getConstraint(siblingSV, domain); return constraint.equals(siblingConstraint); }); }
private Flow flowForNullableMethodParameters(ExplodedGraph.Node node) { if (!node.edges().isEmpty() || !domains.contains(ObjectConstraint.class)) { return Flow.empty(); } Flow.Builder flowBuilder = Flow.builder(); trackedSymbols.forEach(symbol -> { SymbolicValue sv = node.programState.getValue(symbol); if (sv == null) { return; } ObjectConstraint startConstraint = node.programState.getConstraint(sv, ObjectConstraint.class); if (startConstraint != null && isMethodParameter(symbol)) { String msg = IMPLIES_CAN_BE_MSG; if (ObjectConstraint.NOT_NULL == startConstraint) { msg = "Implies '%s' can not be %s."; } flowBuilder.add(new JavaFileScannerContext.Location(String.format(msg, symbol.name(), "null"), ((VariableTree) symbol.declaration()).simpleName())); } }); return flowBuilder.build(); }
private boolean visitedAllParents(ExplodedGraph.Edge edge) { return edge.parent.edges().stream().allMatch(visited::contains); }
private boolean assignedFromYieldWithUncertainResult(Constraint constraint, Node node) { return node.edges().stream().noneMatch(edge -> isConstraintOnlyPossibleResult(constraint, edge)); }
/** * Returns node associated with given (programPoint,programState) pair. If no node for this pair exists, it is created. */ public Node node(ProgramPoint programPoint, @Nullable ProgramState programState) { Node result = new Node(programPoint, programState, this); Node cached = nodes.get(result); if (cached != null) { cached.isNew = false; return cached; } result.isNew = true; nodes.put(result, result); nodesByProgramPoint.put(programPoint, result); return result; }
/** * Returns node associated with given (programPoint,programState) pair. If no node for this pair exists, it is created. */ Node getNode(ProgramPoint programPoint, @Nullable ProgramState programState) { Node result = new Node(programPoint, programState); Node cached = nodes.get(result); if (cached != null) { cached.isNew = false; return cached; } result.isNew = true; nodes.put(result, result); return result; }
private boolean visitedAllParents(ExplodedGraph.Edge edge) { return edge.parent.edges().stream().allMatch(visited::contains); }
@Nullable public Node parent() { return parents().stream().findFirst().orElse(null); }
private boolean assignedFromYieldWithUncertainResult(Constraint constraint, Node node) { return node.edges().stream().noneMatch(edge -> isConstraintOnlyPossibleResult(constraint, edge)); }
private static Set<Flow> flowFromNode(ExplodedGraph.Node node) { List<Class<? extends Constraint>> domains = Lists.newArrayList(ObjectConstraint.class, BooleanConstraint.class); return FlowComputation.flow(node.parent(), node.programState.peekValue(), domains, node.programState.peekValueSymbol().symbol); }
public void addExceptionalYield(SymbolicValue target, ProgramState exceptionalState, String exceptionFullyQualifiedName, SECheck check) { // in order to create such Exceptional Yield, a parameter of the method has to be the cause of the exception if (methodBehavior != null && methodBehavior.parameters().contains(target)) { Type exceptionType = semanticModel.getClassType(exceptionFullyQualifiedName); ProgramState newExceptionalState = exceptionalState.clearStack().stackValue(constraintManager.createExceptionalSymbolicValue(exceptionType)); ExplodedGraph.Node exitNode = explodedGraph.node(node.programPoint, newExceptionalState); methodBehavior.createExceptionalCheckBasedYield(target, exitNode, exceptionFullyQualifiedName, check); exitNode.addParent(node, null); } }
private Edge(Node child, Node parent) { Preconditions.checkState(!child.equals(parent)); this.child = child; this.parent = parent; hashcode = Objects.hash(child, parent); }