diff options
Diffstat (limited to 'org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java')
-rw-r--r-- | org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java | 256 |
1 files changed, 81 insertions, 175 deletions
diff --git a/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java b/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java index 5ed04cc..04348ab 100644 --- a/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java +++ b/org.eclipse.cdt.codan.extension/src/org/eclipse/cdt/codan/extension/checkers/CloseOpenedFilesChecker.java @@ -13,32 +13,23 @@ package org.eclipse.cdt.codan.extension.checkers; import java.io.File; import java.net.URI; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.List; +import java.util.LinkedList; import java.util.Map; +import java.util.Queue; import java.util.Set; -import java.util.Stack; import org.eclipse.cdt.codan.core.model.AbstractIndexAstChecker; import org.eclipse.cdt.codan.extension.Activator; import org.eclipse.cdt.codan.extension.ExecutionState; +import org.eclipse.cdt.codan.extension.ExecutionStateClause; import org.eclipse.cdt.codan.extension.PropertyState; import org.eclipse.cdt.codan.extension.SymbolicState; -import org.eclipse.cdt.core.dom.ast.ASTVisitor; -import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; -import org.eclipse.cdt.core.dom.ast.IASTDeclarator; -import org.eclipse.cdt.core.dom.ast.IASTExpression; -import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; -import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression; -import org.eclipse.cdt.core.dom.ast.IASTIdExpression; -import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression; -import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.codan.extension.VariableAssignmentVisitor; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; -import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; @@ -56,7 +47,7 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { private static final String OPEN = "open"; private static final String CLOSE = "close"; - private Stack<IBlock> worklist; + private Queue<IBlock> worklist; // Property simulation state info for CFG's edges private Map<IControlFlowEdge, Set<SymbolicState>> edgeInfo; @@ -65,17 +56,17 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { private PropertyState uninit; private PropertyState error; private PropertyState opened; + + // Most recent node to cause transition to error state + private IASTNode errorNode; public CloseOpenedFilesChecker() { - worklist = new Stack<IBlock>(); + worklist = new LinkedList<IBlock>(); edgeInfo = new HashMap<IControlFlowEdge, Set<SymbolicState>>(); initFSM(); } public void processAst(IASTTranslationUnit ast) { - // traverse the AST using the visitor pattern - CloseOpenedFilesVisitor visitor = new CloseOpenedFilesVisitor(); - GraphCreator creator = new GraphCreator(); // Retrieve resource corresponding to this translation unit @@ -95,21 +86,22 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { IASTStatement fnBody = cgRoot.getFuncDef().getBody(); IControlFlowGraph cfg = new ControlFlowGraph(fnBody); cfg.buildCFG(); - //cfg.print(); solve(cfg); - - // ast.accept(visitor); + + IControlFlowEdge exitEdge = cfg.getExit().getInEdges()[0]; + for (SymbolicState s : edgeInfo.get(exitEdge)) { + if (s.getPropertyStates().contains(error)) { + // Report problem + reportProblem(errorNode, s.getExecutionState()); + } + } } } private void solve(IControlFlowGraph cfg) { for (IControlFlowEdge edge : cfg.getEdges()) { - IASTNode from = edge.getFrom().getContent(); - IASTNode to = edge.getTo().getContent(); - System.out.println((from != null ? from.getRawSignature() : from) + " -> " + (to != null ? to.getRawSignature() : to)); - // Initialize edgeInfo for each edge Set<SymbolicState> set = new HashSet<SymbolicState>(); edgeInfo.put(edge, set); @@ -124,14 +116,19 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { es.setTop(true); symStates.add(new SymbolicState(propStates, es)); - worklist.push(entryEdge.getTo()); + worklist.add(entryEdge.getTo()); + // XXX Debug + printStates(entryEdge, symStates); while (!worklist.isEmpty()) { - IBlock blk = worklist.pop(); + IBlock blk = worklist.remove(); if (isMerge(blk)) { // Apply flow function for a merge block Set<SymbolicState> newStates = flowMerge(blk, edgeInfo.get(blk.getInEdges()[0]), edgeInfo.get(blk.getInEdges()[1])); add(blk.getOutEdges()[0], newStates); + + // XXX Debug + System.out.println("MRG: " + printStates(blk.getOutEdges()[0], newStates)); } else if (isBranch(blk)) { // Apply flow function for a branch block @@ -142,58 +139,37 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { // Assumes 0th out-edge is true branch, 1st out-edge is false branch add(blk.getOutEdges()[0], newStatesTrue); add(blk.getOutEdges()[1], newStatesFalse); + + // XXX Debug + System.out.println("BR (T): " + printStates(blk.getOutEdges()[0], newStatesTrue)); + System.out.println("BR (F): " + printStates(blk.getOutEdges()[1], newStatesFalse)); } else { // Apply flow function for a normal block Set<SymbolicState> newStates = flowOther(blk, edgeInfo.get(blk.getInEdges()[0])); - printStates(newStates); // Don't process the null exit block if (!blk.equals(cfg.getExit())) { add(blk.getOutEdges()[0], newStates); + // XXX Debug + System.out.println("OTH: " + printStates(blk.getOutEdges()[0], newStates)); } } } } - private void printStates(Set<SymbolicState> states) { + private String printStates(IControlFlowEdge edge, Set<SymbolicState> states) { StringBuffer buf = new StringBuffer(); - for (SymbolicState s : states) { - buf.append("{"); - for (PropertyState ps : s.getPropertyStates()) { - buf.append("{"); - if (ps.equals(uninit)) { - buf.append("$u"); - } - else if (ps.equals(opened)) { - buf.append("o"); - } - else /* error */ { - buf.append("$e"); - } - buf.append(", "); - } - buf.replace(buf.length() - 2, buf.length(), "}, "); - if (s.getExecutionState().isTop()) { - buf.append("[TOP]"); - } - else if (s.getExecutionState().isBottom()) { - buf.append("[BOT]"); - } - else { - buf.append("["); - ExecutionState es = s.getExecutionState(); - IASTNode[] nodes = es.getClauses(); - for (IASTNode n : nodes) { - buf.append(n.getRawSignature()); - buf.append(" "); - } - buf.replace(buf.length() - 1, buf.length(), "]"); - } - buf.append("}"); - } - System.out.println(buf.toString()); + IASTNode from = edge.getFrom().getContent(); + IASTNode to = edge.getTo().getContent(); + buf.append("{"); + buf.append(from == null ? from : from.getRawSignature()); + buf.append(" -> "); + buf.append(to == null ? to : to.getRawSignature()); + buf.append("} = "); + buf.append(states); + return buf.toString(); } private Set<SymbolicState> flowMerge(IBlock blk, Set<SymbolicState> ss1, @@ -228,37 +204,34 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { } private SymbolicState transferBranch(IBlock blk, SymbolicState s, boolean value) { - // TODO Auto-generated method stub - return s; + IASTNode node = blk.getContent(); + + SymbolicState ret = s.copy(); + if (node != null) { + // TODO Theorem Prover goes here! / Determine if branch is feasible + + // Modify execution state according to branch condition + // *N.B.* content for condition IBlock is condition expression itself + ret.getExecutionState().addClause(new ExecutionStateClause(node, value)); + } + + return ret; } private SymbolicState transferOther(IBlock blk, SymbolicState s) { IASTNode node = blk.getContent(); - if (node instanceof IASTExpressionStatement) { + if (node != null) { // Process property state transition Set<PropertyState> oldStates = s.getPropertyStates(); Set<PropertyState> newStates = new HashSet<PropertyState>(); for (PropertyState state : oldStates) { - newStates.add(state.transition((IASTStatement) node)); + newStates.add(state.transition(node)); } s.setPropertyStates(newStates); - // Check if we have an assignment statement - IASTExpression expr = ((IASTExpressionStatement) node).getExpression(); - if (expr instanceof IASTBinaryExpression) { - IASTBinaryExpression binExpr = (IASTBinaryExpression) expr; - int op = binExpr.getOperator(); - - // Check operator is an assignment operator - if (op >= IASTBinaryExpression.op_assign - && op <= IASTBinaryExpression.op_binaryOrAssign) { - IASTExpression o1 = binExpr.getOperand1(); - if (o1 instanceof IASTIdExpression) { - s.getExecutionState().addClause(((IASTIdExpression) o1).getName()); - } - } - } + // Modify execution state according to variable assignments + node.accept(new VariableAssignmentVisitor(s.getExecutionState())); } return s; } @@ -267,57 +240,64 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { Set<SymbolicState> ss) { if (!edgeInfo.get(edge).equals(ss)) { edgeInfo.put(edge, ss); - worklist.push(edge.getTo()); + + // No duplicates + IBlock next = edge.getTo(); + if (!worklist.contains(next)) { + worklist.add(next); + } } } private void initFSM() { - uninit = new PropertyState() { + uninit = new PropertyState("$u") { @Override - public PropertyState transition(IASTStatement stmt) { + public PropertyState transition(IASTNode node) { PropertyState dest = uninit; - if (containsOpen(stmt)) { + if (containsOpen(node)) { dest = opened; } - else if (containsClose(stmt)) { + else if (containsClose(node)) { dest = error; + errorNode = node; } return dest; } }; - opened = new PropertyState() { + opened = new PropertyState("o") { @Override - public PropertyState transition(IASTStatement stmt) { + public PropertyState transition(IASTNode node) { PropertyState dest = opened; - if (containsOpen(stmt)) { + if (containsOpen(node)) { dest = error; + errorNode = node; } - if (containsClose(stmt)) { + if (containsClose(node)) { dest = uninit; } return dest; } }; - error = new PropertyState() { + error = new PropertyState("$e") { @Override - public PropertyState transition(IASTStatement stmt) { + public PropertyState transition(IASTNode node) { return error; } }; } - protected boolean containsOpen(IASTStatement stmt) { + protected boolean containsOpen(IASTNode node) { // TODO Examine more than just name - FunctionNameParser parser = new FunctionNameParser(stmt, OPEN); + FunctionNameParser parser = new FunctionNameParser(node, OPEN); return parser.matches(); } - protected boolean containsClose(IASTStatement stmt) { + protected boolean containsClose(IASTNode node) { // TODO Examine more than just name - FunctionNameParser parser = new FunctionNameParser(stmt, CLOSE); + FunctionNameParser parser = new FunctionNameParser(node, CLOSE); return parser.matches(); } @@ -329,82 +309,8 @@ public class CloseOpenedFilesChecker extends AbstractIndexAstChecker { return blk.getInEdges().length > 1; } - private void reportProblem(IASTName closeFD) { - String message = MessageFormat.format("File descriptor \"{0}\" has not been opened", closeFD.toString()); - reportProblem(ERR_ID, closeFD, message); + private void reportProblem(IASTNode node, ExecutionState condition) { + String message = MessageFormat.format("Improper use of open/close given {0}.", condition); + reportProblem(ERR_ID, node, message); } - - - class CloseOpenedFilesVisitor extends ASTVisitor { - - private List<IASTName> openedFDs; - - public CloseOpenedFilesVisitor() { - openedFDs = new ArrayList<IASTName>(); - shouldVisitExpressions = true; - } - - @Override - public int visit(IASTExpression expression) { - if (expression instanceof IASTFunctionCallExpression) { - IASTFunctionCallExpression callExpression = (IASTFunctionCallExpression) expression; - IASTExpression funcName = callExpression.getFunctionNameExpression(); - if (funcName instanceof IASTIdExpression) { - IASTName name = ((IASTIdExpression) funcName).getName(); - String simpleName = String.valueOf(name.getSimpleID()); - if (simpleName.equals(OPEN)) { - IASTNode parent = callExpression.getParent(); - // Handle initialization in declaration - if (parent instanceof IASTInitializerExpression) { - parent = parent.getParent(); - if (parent instanceof IASTDeclarator) { - openedFDs.add(((IASTDeclarator) parent).getName()); - } - } - // Assignment after declaration - else if (parent instanceof IASTBinaryExpression) { - IASTExpression op2 = ((IASTBinaryExpression) parent).getOperand2(); - int operator = ((IASTBinaryExpression) parent).getOperator(); - if (callExpression.equals(op2) && operator == IASTBinaryExpression.op_assign) { - IASTExpression op1 = ((IASTBinaryExpression) parent).getOperand1(); - if (op1 instanceof IASTIdExpression) { - openedFDs.add(((IASTIdExpression) op1).getName()); - } - } - } - } - else if (simpleName.equals(CLOSE)) { - IASTExpression paramExpression = callExpression.getParameterExpression(); - if (paramExpression instanceof IASTIdExpression) { - IASTName fd = ((IASTIdExpression) paramExpression).getName(); - // Add only if no matching opened FD - boolean match = false; - for (int i = 0; !match && i < openedFDs.size(); i++) { - IASTName opened = openedFDs.get(i); - match = matchingFileDescriptors(fd, opened); - } - - if (!match) { - reportProblem(fd); - } - } - } - } - - return PROCESS_SKIP; - } - else { - return PROCESS_CONTINUE; - } - } - - private boolean matchingFileDescriptors(IASTName closeFD, IASTName openFD) { - // FIXME elaborate - IBinding closeBinding = closeFD.getBinding(); - IBinding openBinding = openFD.getBinding(); - - return openBinding != null && closeBinding != null && openBinding.equals(closeBinding); - } - } - } |