X-Git-Url: http://plrg.eecs.uci.edu/git/?p=IRC.git;a=blobdiff_plain;f=Robust%2Fsrc%2FAnalysis%2FSSJava%2FFlowDownCheck.java;h=e2dc738475c1005fe4f14568f4c8109f369e6994;hp=3edbd818ce63d00d942e194ea5b0396d52d32712;hb=03e4ef747b4dc3b230bc431ad476c773f09751d4;hpb=3cc80ebdf6feb3d663d446ff4e330a9a178463fd diff --git a/Robust/src/Analysis/SSJava/FlowDownCheck.java b/Robust/src/Analysis/SSJava/FlowDownCheck.java index 3edbd818..e2dc7384 100644 --- a/Robust/src/Analysis/SSJava/FlowDownCheck.java +++ b/Robust/src/Analysis/SSJava/FlowDownCheck.java @@ -1,6 +1,8 @@ package Analysis.SSJava; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; @@ -9,6 +11,8 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.Vector; +import Analysis.SSJava.FlowDownCheck.ComparisonResult; +import Analysis.SSJava.FlowDownCheck.CompositeLattice; import IR.AnnotationDescriptor; import IR.ClassDescriptor; import IR.Descriptor; @@ -39,29 +43,52 @@ import IR.Tree.NameNode; import IR.Tree.OpNode; import IR.Tree.ReturnNode; import IR.Tree.SubBlockNode; +import IR.Tree.SwitchBlockNode; +import IR.Tree.SwitchStatementNode; +import IR.Tree.SynchronizedNode; import IR.Tree.TertiaryNode; import IR.Tree.TreeNode; +import Util.Pair; public class FlowDownCheck { - static State state; + State state; static SSJavaAnalysis ssjava; - HashSet toanalyze; + Set toanalyze; + List toanalyzeList; + + Set toanalyzeMethod; + List toanalyzeMethodList; // mapping from 'descriptor' to 'composite location' Hashtable d2loc; + Hashtable md2ReturnLoc; + Hashtable md2ReturnLocGen; + // mapping from 'locID' to 'class descriptor' Hashtable fieldLocName2cd; + boolean deterministic = true; + public FlowDownCheck(SSJavaAnalysis ssjava, State state) { this.ssjava = ssjava; this.state = state; - this.toanalyze = new HashSet(); + if (deterministic) { + this.toanalyzeList = new ArrayList(); + } else { + this.toanalyze = new HashSet(); + } + if (deterministic) { + this.toanalyzeMethodList = new ArrayList(); + } else { + this.toanalyzeMethod = new HashSet(); + } this.d2loc = new Hashtable(); this.fieldLocName2cd = new Hashtable(); - init(); + this.md2ReturnLoc = new Hashtable(); + this.md2ReturnLocGen = new Hashtable(); } public void init() { @@ -84,67 +111,248 @@ public class FlowDownCheck { } - public void flowDownCheck() { + public boolean toAnalyzeIsEmpty() { + if (deterministic) { + return toanalyzeList.isEmpty(); + } else { + return toanalyze.isEmpty(); + } + } + + public ClassDescriptor toAnalyzeNext() { + if (deterministic) { + return toanalyzeList.remove(0); + } else { + ClassDescriptor cd = toanalyze.iterator().next(); + toanalyze.remove(cd); + return cd; + } + } + + public void setupToAnalyze() { SymbolTable classtable = state.getClassSymbolTable(); + if (deterministic) { + toanalyzeList.clear(); + toanalyzeList.addAll(classtable.getValueSet()); + Collections.sort(toanalyzeList, new Comparator() { + public int compare(ClassDescriptor o1, ClassDescriptor o2) { + return o1.getClassName().compareTo(o2.getClassName()); + } + }); + } else { + toanalyze.clear(); + toanalyze.addAll(classtable.getValueSet()); + } + } + + public void setupToAnalazeMethod(ClassDescriptor cd) { + + SymbolTable methodtable = cd.getMethodTable(); + if (deterministic) { + toanalyzeMethodList.clear(); + toanalyzeMethodList.addAll(methodtable.getValueSet()); + Collections.sort(toanalyzeMethodList, new Comparator() { + public int compare(MethodDescriptor o1, MethodDescriptor o2) { + return o1.getSymbol().compareTo(o2.getSymbol()); + } + }); + } else { + toanalyzeMethod.clear(); + toanalyzeMethod.addAll(methodtable.getValueSet()); + } + } + + public boolean toAnalyzeMethodIsEmpty() { + if (deterministic) { + return toanalyzeMethodList.isEmpty(); + } else { + return toanalyzeMethod.isEmpty(); + } + } + + public MethodDescriptor toAnalyzeMethodNext() { + if (deterministic) { + return toanalyzeMethodList.remove(0); + } else { + MethodDescriptor md = toanalyzeMethod.iterator().next(); + toanalyzeMethod.remove(md); + return md; + } + } + + public void flowDownCheck() { // phase 1 : checking declaration node and creating mapping of 'type // desciptor' & 'location' - toanalyze.addAll(classtable.getValueSet()); - toanalyze.addAll(state.getTaskSymbolTable().getValueSet()); - while (!toanalyze.isEmpty()) { - Object obj = toanalyze.iterator().next(); - ClassDescriptor cd = (ClassDescriptor) obj; - toanalyze.remove(cd); + setupToAnalyze(); + + while (!toAnalyzeIsEmpty()) { + ClassDescriptor cd = toAnalyzeNext(); + + if (ssjava.needToBeAnnoated(cd)) { + + ClassDescriptor superDesc = cd.getSuperDesc(); + + if (superDesc != null && (!superDesc.getSymbol().equals("Object"))) { + checkOrderingInheritance(superDesc, cd); + } - if (!cd.isInterface()) { checkDeclarationInClass(cd); - for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { - MethodDescriptor md = (MethodDescriptor) method_it.next(); - try { + + setupToAnalazeMethod(cd); + while (!toAnalyzeMethodIsEmpty()) { + MethodDescriptor md = toAnalyzeMethodNext(); + if (ssjava.needTobeAnnotated(md)) { checkDeclarationInMethodBody(cd, md); - } catch (Error e) { - System.out.println("Error in " + md); - throw e; } } + } } // phase2 : checking assignments - toanalyze.addAll(classtable.getValueSet()); - toanalyze.addAll(state.getTaskSymbolTable().getValueSet()); - while (!toanalyze.isEmpty()) { - Object obj = toanalyze.iterator().next(); - ClassDescriptor cd = (ClassDescriptor) obj; - toanalyze.remove(cd); + setupToAnalyze(); + + while (!toAnalyzeIsEmpty()) { + ClassDescriptor cd = toAnalyzeNext(); - checkClass(cd); - for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { - MethodDescriptor md = (MethodDescriptor) method_it.next(); - try { + setupToAnalazeMethod(cd); + while (!toAnalyzeMethodIsEmpty()) { + MethodDescriptor md = toAnalyzeMethodNext(); + if (ssjava.needTobeAnnotated(md)) { + System.out.println("SSJAVA: Checking assignments: " + md); checkMethodBody(cd, md); - } catch (Error e) { - System.out.println("Error in " + md); - throw e; } } } } + private void checkOrderingInheritance(ClassDescriptor superCd, ClassDescriptor cd) { + // here, we're going to check that sub class keeps same relative orderings + // in respect to super class + + SSJavaLattice superLattice = ssjava.getClassLattice(superCd); + SSJavaLattice subLattice = ssjava.getClassLattice(cd); + + if (superLattice != null) { + // if super class doesn't define lattice, then we don't need to check its + // subclass + if (subLattice == null) { + throw new Error("If a parent class '" + superCd + + "' has a ordering lattice, its subclass '" + cd + "' should have one."); + } + + Set> superPairSet = superLattice.getOrderingPairSet(); + Set> subPairSet = subLattice.getOrderingPairSet(); + + for (Iterator iterator = superPairSet.iterator(); iterator.hasNext();) { + Pair pair = (Pair) iterator.next(); + + if (!subPairSet.contains(pair)) { + throw new Error("Subclass '" + cd + "' does not have the relative ordering '" + + pair.getSecond() + " < " + pair.getFirst() + + "' that is defined by its superclass '" + superCd + "'."); + } + } + } + + MethodLattice superMethodDefaultLattice = ssjava.getMethodDefaultLattice(superCd); + MethodLattice subMethodDefaultLattice = ssjava.getMethodDefaultLattice(cd); + + if (superMethodDefaultLattice != null) { + if (subMethodDefaultLattice == null) { + throw new Error("When a parent class '" + superCd + + "' defines a default method lattice, its subclass '" + cd + "' should define one."); + } + + Set> superPairSet = superMethodDefaultLattice.getOrderingPairSet(); + Set> subPairSet = subMethodDefaultLattice.getOrderingPairSet(); + + for (Iterator iterator = superPairSet.iterator(); iterator.hasNext();) { + Pair pair = (Pair) iterator.next(); + + if (!subPairSet.contains(pair)) { + throw new Error("Subclass '" + cd + "' does not have the relative ordering '" + + pair.getSecond() + " < " + pair.getFirst() + + "' that is defined by its superclass '" + superCd + + "' in the method default lattice."); + } + } + + } + + } + public Hashtable getMap() { return d2loc; } private void checkDeclarationInMethodBody(ClassDescriptor cd, MethodDescriptor md) { BlockNode bn = state.getMethodBody(md); + + // first, check annotations on method parameters + List paramList = new ArrayList(); for (int i = 0; i < md.numParameters(); i++) { // process annotations on method parameters VarDescriptor vd = (VarDescriptor) md.getParameter(i); assignLocationOfVarDescriptor(vd, md, md.getParameterTable(), bn); + paramList.add(d2loc.get(vd)); + } + Vector methodAnnotations = md.getModifiers().getAnnotations(); + + // second, check return location annotation + if (!md.getReturnType().isVoid()) { + CompositeLocation returnLocComp = null; + + boolean hasReturnLocDeclaration = false; + if (methodAnnotations != null) { + for (int i = 0; i < methodAnnotations.size(); i++) { + AnnotationDescriptor an = methodAnnotations.elementAt(i); + if (an.getMarker().equals(ssjava.RETURNLOC)) { + // this case, developer explicitly defines method lattice + String returnLocDeclaration = an.getValue(); + returnLocComp = parseLocationDeclaration(md, null, returnLocDeclaration); + hasReturnLocDeclaration = true; + } + } + } + + if (!hasReturnLocDeclaration) { + // if developer does not define method lattice + // search return location in the method default lattice + String rtrStr = ssjava.getMethodLattice(md).getReturnLoc(); + returnLocComp = new CompositeLocation(new Location(md, rtrStr)); + } + + if (returnLocComp == null) { + throw new Error("Return location is not specified for the method " + md + " at " + + cd.getSourceFileName()); + } + + md2ReturnLoc.put(md, returnLocComp); + + // check this location + MethodLattice methodLattice = ssjava.getMethodLattice(md); + String thisLocId = methodLattice.getThisLoc(); + if (thisLocId == null) { + throw new Error("Method '" + md + "' does not have the definition of 'this' location at " + + md.getClassDesc().getSourceFileName()); + } + CompositeLocation thisLoc = new CompositeLocation(new Location(md, thisLocId)); + paramList.add(0, thisLoc); + + System.out.println("### ReturnLocGenerator=" + md); + System.out.println("### md2ReturnLoc.get(md)=" + md2ReturnLoc.get(md)); + md2ReturnLocGen.put(md, new ReturnLocGenerator(md2ReturnLoc.get(md), md, paramList, md + + " of " + cd.getSourceFileName())); } + + // fourth, check declarations inside of method + checkDeclarationInBlockNode(md, md.getParameterTable(), bn); + } private void checkDeclarationInBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) { @@ -170,9 +378,43 @@ public class FlowDownCheck { case Kind.LoopNode: checkDeclarationInLoopNode(md, nametable, (LoopNode) bsn); break; + + case Kind.IfStatementNode: + checkDeclarationInIfStatementNode(md, nametable, (IfStatementNode) bsn); + return; + + case Kind.SwitchStatementNode: + checkDeclarationInSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn); + return; + + case Kind.SynchronizedNode: + checkDeclarationInSynchronizedNode(md, nametable, (SynchronizedNode) bsn); + return; + } } + private void checkDeclarationInSynchronizedNode(MethodDescriptor md, SymbolTable nametable, + SynchronizedNode sbn) { + checkDeclarationInBlockNode(md, nametable, sbn.getBlockNode()); + } + + private void checkDeclarationInSwitchStatementNode(MethodDescriptor md, SymbolTable nametable, + SwitchStatementNode ssn) { + BlockNode sbn = ssn.getSwitchBody(); + for (int i = 0; i < sbn.size(); i++) { + SwitchBlockNode node = (SwitchBlockNode) sbn.get(i); + checkDeclarationInBlockNode(md, nametable, node.getSwitchBlockStatement()); + } + } + + private void checkDeclarationInIfStatementNode(MethodDescriptor md, SymbolTable nametable, + IfStatementNode isn) { + checkDeclarationInBlockNode(md, nametable, isn.getTrueBlock()); + if (isn.getFalseBlock() != null) + checkDeclarationInBlockNode(md, nametable, isn.getFalseBlock()); + } + private void checkDeclarationInLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) { if (ln.getType() == LoopNode.FORLOOP) { @@ -191,87 +433,140 @@ public class FlowDownCheck { private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) { BlockNode bn = state.getMethodBody(md); - checkLocationFromBlockNode(md, md.getParameterTable(), bn); + checkLocationFromBlockNode(md, md.getParameterTable(), bn, null); + } + + private String generateErrorMessage(ClassDescriptor cd, TreeNode tn) { + if (tn != null) { + return cd.getSourceFileName() + "::" + tn.getNumLine(); + } else { + return cd.getSourceFileName(); + } + } private CompositeLocation checkLocationFromBlockNode(MethodDescriptor md, SymbolTable nametable, - BlockNode bn) { + BlockNode bn, CompositeLocation constraint) { bn.getVarTable().setParent(nametable); - // it will return the lowest location in the block node - CompositeLocation lowestLoc = null; for (int i = 0; i < bn.size(); i++) { BlockStatementNode bsn = bn.get(i); - CompositeLocation bLoc = checkLocationFromBlockStatementNode(md, bn.getVarTable(), bsn); - if (lowestLoc == null) { - lowestLoc = bLoc; - } else { - if (!bLoc.isEmpty()) { - if (CompositeLattice.isGreaterThan(lowestLoc, bLoc)) { - lowestLoc = bLoc; - } - } - } + checkLocationFromBlockStatementNode(md, bn.getVarTable(), bsn, constraint); } - return lowestLoc; + return new CompositeLocation(); + } private CompositeLocation checkLocationFromBlockStatementNode(MethodDescriptor md, - SymbolTable nametable, BlockStatementNode bsn) { + SymbolTable nametable, BlockStatementNode bsn, CompositeLocation constraint) { CompositeLocation compLoc = null; switch (bsn.kind()) { case Kind.BlockExpressionNode: - compLoc = checkLocationFromBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn); + compLoc = + checkLocationFromBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn, constraint); break; case Kind.DeclarationNode: - compLoc = checkLocationFromDeclarationNode(md, nametable, (DeclarationNode) bsn); + compLoc = checkLocationFromDeclarationNode(md, nametable, (DeclarationNode) bsn, constraint); break; case Kind.IfStatementNode: - compLoc = checkLocationFromIfStatementNode(md, nametable, (IfStatementNode) bsn); + compLoc = checkLocationFromIfStatementNode(md, nametable, (IfStatementNode) bsn, constraint); break; case Kind.LoopNode: - compLoc = checkLocationFromLoopNode(md, nametable, (LoopNode) bsn); + compLoc = checkLocationFromLoopNode(md, nametable, (LoopNode) bsn, constraint); break; case Kind.ReturnNode: - compLoc = checkLocationFromReturnNode(md, nametable, (ReturnNode) bsn); + compLoc = checkLocationFromReturnNode(md, nametable, (ReturnNode) bsn, constraint); break; case Kind.SubBlockNode: - compLoc = checkLocationFromSubBlockNode(md, nametable, (SubBlockNode) bsn); + compLoc = checkLocationFromSubBlockNode(md, nametable, (SubBlockNode) bsn, constraint); break; - // case Kind.ContinueBreakNode: - // checkLocationFromContinueBreakNode(md, nametable,(ContinueBreakNode) - // bsn); - // return null; + case Kind.ContinueBreakNode: + compLoc = new CompositeLocation(); + break; + + case Kind.SwitchStatementNode: + compLoc = + checkLocationFromSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn, constraint); + } return compLoc; } - private CompositeLocation checkLocationFromReturnNode(MethodDescriptor md, SymbolTable nametable, - ReturnNode rn) { + private CompositeLocation checkLocationFromSwitchStatementNode(MethodDescriptor md, + SymbolTable nametable, SwitchStatementNode ssn, CompositeLocation constraint) { + ClassDescriptor cd = md.getClassDesc(); - CompositeLocation loc = new CompositeLocation(); + CompositeLocation condLoc = + checkLocationFromExpressionNode(md, nametable, ssn.getCondition(), new CompositeLocation(), + constraint, false); + BlockNode sbn = ssn.getSwitchBody(); + + constraint = generateNewConstraint(constraint, condLoc); + + for (int i = 0; i < sbn.size(); i++) { + checkLocationFromSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i), constraint); + } + return new CompositeLocation(); + } + + private CompositeLocation checkLocationFromSwitchBlockNode(MethodDescriptor md, + SymbolTable nametable, SwitchBlockNode sbn, CompositeLocation constraint) { + + CompositeLocation blockLoc = + checkLocationFromBlockNode(md, nametable, sbn.getSwitchBlockStatement(), constraint); + + return blockLoc; + + } + + private CompositeLocation checkLocationFromReturnNode(MethodDescriptor md, SymbolTable nametable, + ReturnNode rn, CompositeLocation constraint) { ExpressionNode returnExp = rn.getReturnExpression(); - if (rn == null || hasOnlyLiteralValue(returnExp)) { - // when it returns literal value, return node has "bottom" location no - // matter what it is going to return. - loc.addLocation(Location.createBottomLocation(md)); - } else { - loc = checkLocationFromExpressionNode(md, nametable, returnExp, loc); + CompositeLocation returnValueLoc; + if (returnExp != null) { + returnValueLoc = + checkLocationFromExpressionNode(md, nametable, returnExp, new CompositeLocation(), + constraint, false); + + // if this return statement is inside branch, return value has an implicit + // flow from conditional location + if (constraint != null) { + Set inputGLB = new HashSet(); + inputGLB.add(returnValueLoc); + inputGLB.add(constraint); + returnValueLoc = + CompositeLattice.calculateGLB(inputGLB, generateErrorMessage(md.getClassDesc(), rn)); + } + + // check if return value is equal or higher than RETRUNLOC of method + // declaration annotation + CompositeLocation declaredReturnLoc = md2ReturnLoc.get(md); + + int compareResult = + CompositeLattice.compare(returnValueLoc, declaredReturnLoc, false, + generateErrorMessage(md.getClassDesc(), rn)); + + if (compareResult == ComparisonResult.LESS || compareResult == ComparisonResult.INCOMPARABLE) { + throw new Error( + "Return value location is not equal or higher than the declaraed return location at " + + md.getClassDesc().getSourceFileName() + "::" + rn.getNumLine()); + } } - return loc; + + return new CompositeLocation(); } - private boolean hasOnlyLiteralValue(ExpressionNode returnExp) { - if (returnExp.kind() == Kind.LiteralNode) { + private boolean hasOnlyLiteralValue(ExpressionNode en) { + if (en.kind() == Kind.LiteralNode) { return true; } else { return false; @@ -279,132 +574,101 @@ public class FlowDownCheck { } private CompositeLocation checkLocationFromLoopNode(MethodDescriptor md, SymbolTable nametable, - LoopNode ln) { + LoopNode ln, CompositeLocation constraint) { ClassDescriptor cd = md.getClassDesc(); if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) { CompositeLocation condLoc = - checkLocationFromExpressionNode(md, nametable, ln.getCondition(), new CompositeLocation()); - addTypeLocation(ln.getCondition().getType(), (condLoc)); + checkLocationFromExpressionNode(md, nametable, ln.getCondition(), + new CompositeLocation(), constraint, false); + addLocationType(ln.getCondition().getType(), (condLoc)); - CompositeLocation bodyLoc = checkLocationFromBlockNode(md, nametable, ln.getBody()); + constraint = generateNewConstraint(constraint, condLoc); + checkLocationFromBlockNode(md, nametable, ln.getBody(), constraint); - if (!CompositeLattice.isGreaterThan(condLoc, bodyLoc)) { - // loop condition should be higher than loop body - throw new Error( - "The location of the while-condition statement is lower than the loop body at " - + cd.getSourceFileName() + ":" + ln.getCondition().getNumLine()); - } - - return bodyLoc; + return new CompositeLocation(); } else { - // check for loop case + // check 'for loop' case BlockNode bn = ln.getInitializer(); bn.getVarTable().setParent(nametable); // calculate glb location of condition and update statements CompositeLocation condLoc = checkLocationFromExpressionNode(md, bn.getVarTable(), ln.getCondition(), - new CompositeLocation()); - addTypeLocation(ln.getCondition().getType(), condLoc); - - CompositeLocation updateLoc = - checkLocationFromBlockNode(md, bn.getVarTable(), ln.getUpdate()); + new CompositeLocation(), constraint, false); + addLocationType(ln.getCondition().getType(), condLoc); - Set glbInputSet = new HashSet(); - glbInputSet.add(condLoc); - glbInputSet.add(updateLoc); + constraint = generateNewConstraint(constraint, condLoc); - CompositeLocation glbLocOfForLoopCond = CompositeLattice.calculateGLB(glbInputSet); + checkLocationFromBlockNode(md, bn.getVarTable(), ln.getUpdate(), constraint); + checkLocationFromBlockNode(md, bn.getVarTable(), ln.getBody(), constraint); - // check location of 'forloop' body - CompositeLocation blockLoc = checkLocationFromBlockNode(md, bn.getVarTable(), ln.getBody()); + return new CompositeLocation(); - if (blockLoc == null) { - // when there is no statement in the loop body - return glbLocOfForLoopCond; - } - - if (!CompositeLattice.isGreaterThan(glbLocOfForLoopCond, blockLoc)) { - throw new Error( - "The location of the for-condition statement is lower than the for-loop body at " - + cd.getSourceFileName() + ":" + ln.getCondition().getNumLine()); - } - return blockLoc; } } private CompositeLocation checkLocationFromSubBlockNode(MethodDescriptor md, - SymbolTable nametable, SubBlockNode sbn) { - CompositeLocation compLoc = checkLocationFromBlockNode(md, nametable, sbn.getBlockNode()); + SymbolTable nametable, SubBlockNode sbn, CompositeLocation constraint) { + CompositeLocation compLoc = + checkLocationFromBlockNode(md, nametable, sbn.getBlockNode(), constraint); return compLoc; } - private CompositeLocation checkLocationFromIfStatementNode(MethodDescriptor md, - SymbolTable nametable, IfStatementNode isn) { + private CompositeLocation generateNewConstraint(CompositeLocation currentCon, + CompositeLocation newCon) { - ClassDescriptor localCD = md.getClassDesc(); - Set glbInputSet = new HashSet(); + if (currentCon == null) { + return newCon; + } else { + // compute GLB of current constraint and new constraint + Set inputSet = new HashSet(); + inputSet.add(currentCon); + inputSet.add(newCon); + return CompositeLattice.calculateGLB(inputSet, ""); + } - CompositeLocation condLoc = - checkLocationFromExpressionNode(md, nametable, isn.getCondition(), new CompositeLocation()); + } - addTypeLocation(isn.getCondition().getType(), condLoc); - glbInputSet.add(condLoc); + private CompositeLocation checkLocationFromIfStatementNode(MethodDescriptor md, + SymbolTable nametable, IfStatementNode isn, CompositeLocation constraint) { - CompositeLocation locTrueBlock = checkLocationFromBlockNode(md, nametable, isn.getTrueBlock()); - glbInputSet.add(locTrueBlock); + CompositeLocation condLoc = + checkLocationFromExpressionNode(md, nametable, isn.getCondition(), new CompositeLocation(), + constraint, false); - // here, the location of conditional block should be higher than the - // location of true/false blocks + addLocationType(isn.getCondition().getType(), condLoc); - if (!CompositeLattice.isGreaterThan(condLoc, locTrueBlock)) { - // error - throw new Error( - "The location of the if-condition statement is lower than the conditional block at " - + localCD.getSourceFileName() + ":" + isn.getCondition().getNumLine()); - } + constraint = generateNewConstraint(constraint, condLoc); + checkLocationFromBlockNode(md, nametable, isn.getTrueBlock(), constraint); if (isn.getFalseBlock() != null) { - CompositeLocation locFalseBlock = - checkLocationFromBlockNode(md, nametable, isn.getFalseBlock()); - glbInputSet.add(locFalseBlock); - - if (!CompositeLattice.isGreaterThan(condLoc, locFalseBlock)) { - // error - throw new Error( - "The location of the if-condition statement is lower than the conditional block at " - + localCD.getSourceFileName() + ":" + isn.getCondition().getNumLine()); - } - + checkLocationFromBlockNode(md, nametable, isn.getFalseBlock(), constraint); } - // return GLB location of condition, true, and false block - CompositeLocation glbLoc = CompositeLattice.calculateGLB(glbInputSet); - - return glbLoc; + return new CompositeLocation(); } private CompositeLocation checkLocationFromDeclarationNode(MethodDescriptor md, - SymbolTable nametable, DeclarationNode dn) { + SymbolTable nametable, DeclarationNode dn, CompositeLocation constraint) { VarDescriptor vd = dn.getVarDescriptor(); CompositeLocation destLoc = d2loc.get(vd); - ClassDescriptor localCD = md.getClassDesc(); if (dn.getExpression() != null) { CompositeLocation expressionLoc = checkLocationFromExpressionNode(md, nametable, dn.getExpression(), - new CompositeLocation()); - addTypeLocation(dn.getExpression().getType(), expressionLoc); + new CompositeLocation(), constraint, false); + // addTypeLocation(dn.getExpression().getType(), expressionLoc); if (expressionLoc != null) { // checking location order - if (!CompositeLattice.isGreaterThan(expressionLoc, destLoc)) { + if (!CompositeLattice.isGreaterThan(expressionLoc, destLoc, + generateErrorMessage(md.getClassDesc(), dn))) { throw new Error("The value flow from " + expressionLoc + " to " + destLoc + " does not respect location hierarchy on the assignment " + dn.printNode(0) + " at " + md.getClassDesc().getSourceFileName() + "::" + dn.getNumLine()); @@ -414,14 +678,7 @@ public class FlowDownCheck { } else { - // if (destLoc instanceof Location) { - // CompositeLocation comp = new CompositeLocation(); - // comp.addLocation(destLoc); - // return comp; - // } else { - // return (CompositeLocation) destLoc; - // } - return destLoc; + return new CompositeLocation(); } @@ -433,33 +690,36 @@ public class FlowDownCheck { } private CompositeLocation checkLocationFromBlockExpressionNode(MethodDescriptor md, - SymbolTable nametable, BlockExpressionNode ben) { + SymbolTable nametable, BlockExpressionNode ben, CompositeLocation constraint) { CompositeLocation compLoc = - checkLocationFromExpressionNode(md, nametable, ben.getExpression(), null); + checkLocationFromExpressionNode(md, nametable, ben.getExpression(), null, constraint, false); // addTypeLocation(ben.getExpression().getType(), compLoc); return compLoc; } private CompositeLocation checkLocationFromExpressionNode(MethodDescriptor md, - SymbolTable nametable, ExpressionNode en, CompositeLocation loc) { + SymbolTable nametable, ExpressionNode en, CompositeLocation loc, + CompositeLocation constraint, boolean isLHS) { CompositeLocation compLoc = null; switch (en.kind()) { case Kind.AssignmentNode: - compLoc = checkLocationFromAssignmentNode(md, nametable, (AssignmentNode) en, loc); + compLoc = + checkLocationFromAssignmentNode(md, nametable, (AssignmentNode) en, loc, constraint); break; case Kind.FieldAccessNode: - compLoc = checkLocationFromFieldAccessNode(md, nametable, (FieldAccessNode) en, loc); + compLoc = + checkLocationFromFieldAccessNode(md, nametable, (FieldAccessNode) en, loc, constraint); break; case Kind.NameNode: - compLoc = checkLocationFromNameNode(md, nametable, (NameNode) en, loc); + compLoc = checkLocationFromNameNode(md, nametable, (NameNode) en, loc, constraint); break; case Kind.OpNode: - compLoc = checkLocationFromOpNode(md, nametable, (OpNode) en); + compLoc = checkLocationFromOpNode(md, nametable, (OpNode) en, constraint); break; case Kind.CreateObjectNode: @@ -467,7 +727,8 @@ public class FlowDownCheck { break; case Kind.ArrayAccessNode: - compLoc = checkLocationFromArrayAccessNode(md, nametable, (ArrayAccessNode) en); + compLoc = + checkLocationFromArrayAccessNode(md, nametable, (ArrayAccessNode) en, constraint, isLHS); break; case Kind.LiteralNode: @@ -475,15 +736,16 @@ public class FlowDownCheck { break; case Kind.MethodInvokeNode: - compLoc = checkLocationFromMethodInvokeNode(md, nametable, (MethodInvokeNode) en); + compLoc = + checkLocationFromMethodInvokeNode(md, nametable, (MethodInvokeNode) en, loc, constraint); break; case Kind.TertiaryNode: - compLoc = checkLocationFromTertiaryNode(md, nametable, (TertiaryNode) en); + compLoc = checkLocationFromTertiaryNode(md, nametable, (TertiaryNode) en, constraint); break; case Kind.CastNode: - compLoc = checkLocationFromCastNode(md, nametable, (CastNode) en); + compLoc = checkLocationFromCastNode(md, nametable, (CastNode) en, constraint); break; // case Kind.InstanceOfNode: @@ -513,35 +775,46 @@ public class FlowDownCheck { } private CompositeLocation checkLocationFromCastNode(MethodDescriptor md, SymbolTable nametable, - CastNode cn) { + CastNode cn, CompositeLocation constraint) { ExpressionNode en = cn.getExpression(); - return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation()); + return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint, + false); } private CompositeLocation checkLocationFromTertiaryNode(MethodDescriptor md, - SymbolTable nametable, TertiaryNode tn) { + SymbolTable nametable, TertiaryNode tn, CompositeLocation constraint) { ClassDescriptor cd = md.getClassDesc(); CompositeLocation condLoc = - checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation()); - addTypeLocation(tn.getCond().getType(), condLoc); + checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation(), + constraint, false); + addLocationType(tn.getCond().getType(), condLoc); CompositeLocation trueLoc = - checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation()); - addTypeLocation(tn.getTrueExpr().getType(), trueLoc); + checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation(), + constraint, false); + addLocationType(tn.getTrueExpr().getType(), trueLoc); CompositeLocation falseLoc = - checkLocationFromExpressionNode(md, nametable, tn.getFalseExpr(), new CompositeLocation()); - addTypeLocation(tn.getFalseExpr().getType(), falseLoc); + checkLocationFromExpressionNode(md, nametable, tn.getFalseExpr(), new CompositeLocation(), + constraint, false); + addLocationType(tn.getFalseExpr().getType(), falseLoc); + + // locations from true/false branches can be TOP when there are only literal + // values + // in this case, we don't need to check flow down rule! // check if condLoc is higher than trueLoc & falseLoc - if (!CompositeLattice.isGreaterThan(condLoc, trueLoc)) { + if (!trueLoc.get(0).isTop() + && !CompositeLattice.isGreaterThan(condLoc, trueLoc, generateErrorMessage(cd, tn))) { throw new Error( "The location of the condition expression is lower than the true expression at " + cd.getSourceFileName() + ":" + tn.getCond().getNumLine()); } - if (!CompositeLattice.isGreaterThan(condLoc, falseLoc)) { + if (!falseLoc.get(0).isTop() + && !CompositeLattice.isGreaterThan(condLoc, falseLoc, + generateErrorMessage(cd, tn.getCond()))) { throw new Error( "The location of the condition expression is lower than the true expression at " + cd.getSourceFileName() + ":" + tn.getCond().getNumLine()); @@ -552,121 +825,276 @@ public class FlowDownCheck { glbInputSet.add(trueLoc); glbInputSet.add(falseLoc); - return CompositeLattice.calculateGLB(glbInputSet); + return CompositeLattice.calculateGLB(glbInputSet, generateErrorMessage(cd, tn)); } private CompositeLocation checkLocationFromMethodInvokeNode(MethodDescriptor md, - SymbolTable nametable, MethodInvokeNode min) { - - // Location baseLoc = null; - // if (min.getBaseName() != null) { - // Descriptor d = nametable.get(min.getBaseName().getSymbol()); - // if (d instanceof VarDescriptor) { - // CompositeLocation varLoc = (CompositeLocation) ((VarDescriptor) - // d).getType().getExtension(); - // return varLoc; - // } else { - // // it is field descriptor - // assert (d instanceof FieldDescriptor); - // CompositeLocation fieldLoc = - // (CompositeLocation) min.getExpression().getType().getExtension(); - // return fieldLoc; - // } - // } else { - // // method invocation starting from this - // MethodLattice methodLattice = ssjava.getMethodLattice(md); - // System.out.println("md=" + md + " lattice=" + methodLattice); - // String thisLocId = methodLattice.getThisLoc(); - // baseLoc = new Location(md, thisLocId); - // } - // System.out.println("BASE LOC=" + baseLoc); - - if (min.numArgs() > 1) { - // caller needs to guarantee that it passes arguments in regarding to - // callee's hierarchy - for (int i = 0; i < min.numArgs(); i++) { - ExpressionNode en = min.getArg(i); - CompositeLocation callerArg1 = - checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation()); + SymbolTable nametable, MethodInvokeNode min, CompositeLocation loc, + CompositeLocation constraint) { + + CompositeLocation baseLocation = null; + if (min.getExpression() != null) { + baseLocation = + checkLocationFromExpressionNode(md, nametable, min.getExpression(), + new CompositeLocation(), constraint, false); + } else { + + if (min.getMethod().isStatic()) { + String globalLocId = ssjava.getMethodLattice(md).getGlobalLoc(); + if (globalLocId == null) { + throw new Error("Method lattice does not define global variable location at " + + generateErrorMessage(md.getClassDesc(), min)); + } + baseLocation = new CompositeLocation(new Location(md, globalLocId)); + } else { + String thisLocId = ssjava.getMethodLattice(md).getThisLoc(); + baseLocation = new CompositeLocation(new Location(md, thisLocId)); + } + } - ClassDescriptor calleecd = min.getMethod().getClassDesc(); - VarDescriptor calleevd = (VarDescriptor) min.getMethod().getParameter(i); - CompositeLocation calleeLoc1 = d2loc.get(calleevd); + checkCalleeConstraints(md, nametable, min, baseLocation, constraint); - if (!callerArg1.get(0).isTop()) { - // here, check if ordering relations among caller's args respect - // ordering relations in-between callee's args - for (int currentIdx = 0; currentIdx < min.numArgs(); currentIdx++) { - if (currentIdx != i) { // skip itself - ExpressionNode argExp = min.getArg(currentIdx); + checkCallerArgumentLocationConstraints(md, nametable, min, baseLocation, constraint); - CompositeLocation callerArg2 = - checkLocationFromExpressionNode(md, nametable, argExp, new CompositeLocation()); + if (!min.getMethod().getReturnType().isVoid()) { + // If method has a return value, compute the highest possible return + // location in the caller's perspective + CompositeLocation ceilingLoc = + computeCeilingLocationForCaller(md, nametable, min, baseLocation, constraint); + return ceilingLoc; + } - VarDescriptor calleevd2 = (VarDescriptor) min.getMethod().getParameter(currentIdx); - CompositeLocation calleeLoc2 = d2loc.get(calleevd2); + return new CompositeLocation(); - boolean callerResult = CompositeLattice.isGreaterThan(callerArg1, callerArg2); - boolean calleeResult = CompositeLattice.isGreaterThan(calleeLoc1, calleeLoc2); + } - if (calleeResult && !callerResult) { - // If calleeLoc1 is higher than calleeLoc2 - // then, caller should have same ordering relation in-bet - // callerLoc1 & callerLoc2 + private void checkCallerArgumentLocationConstraints(MethodDescriptor md, SymbolTable nametable, + MethodInvokeNode min, CompositeLocation baseLoc, CompositeLocation constraint) { + // if parameter location consists of THIS and FIELD location, + // caller should pass an argument that is comparable to the declared + // parameter location + // and is not lower than the declared parameter location in the field + // lattice. - throw new Error("Caller doesn't respect ordering relations among method arguments:" - + md.getClassDesc().getSourceFileName() + ":" + min.getNumLine()); - } + MethodDescriptor calleemd = min.getMethod(); - } - } + List callerArgList = new ArrayList(); + List calleeParamList = new ArrayList(); + + MethodLattice calleeLattice = ssjava.getMethodLattice(calleemd); + Location calleeThisLoc = new Location(calleemd, calleeLattice.getThisLoc()); + + for (int i = 0; i < min.numArgs(); i++) { + ExpressionNode en = min.getArg(i); + CompositeLocation callerArgLoc = + checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint, + false); + callerArgList.add(callerArgLoc); + } + + // setup callee params set + for (int i = 0; i < calleemd.numParameters(); i++) { + VarDescriptor calleevd = (VarDescriptor) calleemd.getParameter(i); + CompositeLocation calleeLoc = d2loc.get(calleevd); + calleeParamList.add(calleeLoc); + } + + String errorMsg = generateErrorMessage(md.getClassDesc(), min); + + for (int i = 0; i < calleeParamList.size(); i++) { + CompositeLocation calleeParamLoc = calleeParamList.get(i); + if (calleeParamLoc.get(0).equals(calleeThisLoc) && calleeParamLoc.getSize() > 1) { + // callee parameter location has field information + CompositeLocation argLocation = + translateCallerLocToCallee(md, calleeThisLoc, callerArgList.get(i),errorMsg); + + if (!CompositeLattice.isGreaterThan(argLocation, calleeParamLoc, errorMsg)) { + throw new Error("Caller argument '" + min.getArg(i).printNode(0) + + "' should be higher than corresponding callee's parameter at " + errorMsg); } } + } + } + + private CompositeLocation translateCallerLocToCallee(MethodDescriptor md, Location calleeThisLoc, + CompositeLocation callerArgLoc,String errorMsg) { + + ClassDescriptor calleeClassDesc = md.getClassDesc(); + CompositeLocation translate = new CompositeLocation(); + + int startIdx = 0; + for (int i = 0; i < callerArgLoc.getSize(); i++) { + if (callerArgLoc.get(i).getDescriptor().equals(calleeClassDesc)) { + startIdx = i; + } } - // all arguments should be higher than the location of return value + if (startIdx == 0) { + // caller arg location doesn't have field information + throw new Error("Caller argument location " + callerArgLoc + + " does not contain field information while callee has ordering constraints on field at "+errorMsg); + } + + translate.addLocation(calleeThisLoc); + + for (int i = startIdx + 1; i < callerArgLoc.getSize(); i++) { + translate.addLocation(callerArgLoc.get(i)); + } + + System.out.println("TRANSLATED=" + translate + " from callerArgLoc=" + callerArgLoc); + + return translate; + } + + private CompositeLocation computeCeilingLocationForCaller(MethodDescriptor md, + SymbolTable nametable, MethodInvokeNode min, CompositeLocation baseLocation, + CompositeLocation constraint) { + List argList = new ArrayList(); + + // by default, method has a THIS parameter + argList.add(baseLocation); - Set inputGLBSet = new HashSet(); for (int i = 0; i < min.numArgs(); i++) { ExpressionNode en = min.getArg(i); CompositeLocation callerArg = - checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation()); - inputGLBSet.add(callerArg); + checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint, + false); + argList.add(callerArg); } - if (inputGLBSet.size() > 0) { - return CompositeLattice.calculateGLB(inputGLBSet); - } else { - // if there are no arguments, - // method invocation from the same class - CompositeLocation compLoc = new CompositeLocation(); - return compLoc; + System.out.println("\n## computeReturnLocation=" + min.getMethod() + " argList=" + argList); + CompositeLocation compLoc = md2ReturnLocGen.get(min.getMethod()).computeReturnLocation(argList); + DeltaLocation delta = new DeltaLocation(compLoc, 1); + System.out.println("##computeReturnLocation=" + delta); + + return delta; + + } + + private void checkCalleeConstraints(MethodDescriptor md, SymbolTable nametable, + MethodInvokeNode min, CompositeLocation callerBaseLoc, CompositeLocation constraint) { + + MethodDescriptor calleemd = min.getMethod(); + + MethodLattice calleeLattice = ssjava.getMethodLattice(calleemd); + CompositeLocation calleeThisLoc = + new CompositeLocation(new Location(calleemd, calleeLattice.getThisLoc())); + + List callerArgList = new ArrayList(); + List calleeParamList = new ArrayList(); + + if (min.numArgs() > 0) { + // caller needs to guarantee that it passes arguments in regarding to + // callee's hierarchy + + // setup caller args set + // first, add caller's base(this) location + callerArgList.add(callerBaseLoc); + // second, add caller's arguments + for (int i = 0; i < min.numArgs(); i++) { + ExpressionNode en = min.getArg(i); + CompositeLocation callerArgLoc = + checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint, + false); + callerArgList.add(callerArgLoc); + } + + // setup callee params set + // first, add callee's this location + calleeParamList.add(calleeThisLoc); + // second, add callee's parameters + for (int i = 0; i < calleemd.numParameters(); i++) { + VarDescriptor calleevd = (VarDescriptor) calleemd.getParameter(i); + CompositeLocation calleeLoc = d2loc.get(calleevd); + calleeParamList.add(calleeLoc); + } + + // here, check if ordering relations among caller's args respect + // ordering relations in-between callee's args + CHECK: for (int i = 0; i < calleeParamList.size(); i++) { + CompositeLocation calleeLoc1 = calleeParamList.get(i); + CompositeLocation callerLoc1 = callerArgList.get(i); + + for (int j = 0; j < calleeParamList.size(); j++) { + if (i != j) { + CompositeLocation calleeLoc2 = calleeParamList.get(j); + CompositeLocation callerLoc2 = callerArgList.get(j); + + if (callerLoc1.get(callerLoc1.getSize() - 1).isTop() + || callerLoc2.get(callerLoc2.getSize() - 1).isTop()) { + continue CHECK; + } + + int callerResult = + CompositeLattice.compare(callerLoc1, callerLoc2, true, + generateErrorMessage(md.getClassDesc(), min)); + int calleeResult = + CompositeLattice.compare(calleeLoc1, calleeLoc2, true, + generateErrorMessage(md.getClassDesc(), min)); + + if (calleeResult == ComparisonResult.GREATER + && callerResult != ComparisonResult.GREATER) { + // If calleeLoc1 is higher than calleeLoc2 + // then, caller should have same ordering relation in-bet + // callerLoc1 & callerLoc2 + + String paramName1, paramName2; + + if (i == 0) { + paramName1 = "'THIS'"; + } else { + paramName1 = "'parameter " + calleemd.getParamName(i - 1) + "'"; + } + + if (j == 0) { + paramName2 = "'THIS'"; + } else { + paramName2 = "'parameter " + calleemd.getParamName(j - 1) + "'"; + } + + throw new Error( + "Caller doesn't respect an ordering relation among method arguments: callee expects that " + + paramName1 + " should be higher than " + paramName2 + " in " + calleemd + + " at " + md.getClassDesc().getSourceFileName() + ":" + min.getNumLine()); + } + } + + } + } + } } private CompositeLocation checkLocationFromArrayAccessNode(MethodDescriptor md, - SymbolTable nametable, ArrayAccessNode aan) { - - // return glb location of array itself and index + SymbolTable nametable, ArrayAccessNode aan, CompositeLocation constraint, boolean isLHS) { ClassDescriptor cd = md.getClassDesc(); - Set glbInputSet = new HashSet(); - CompositeLocation arrayLoc = - checkLocationFromExpressionNode(md, nametable, aan.getExpression(), new CompositeLocation()); - addTypeLocation(aan.getExpression().getType(), arrayLoc); - glbInputSet.add(arrayLoc); + checkLocationFromExpressionNode(md, nametable, aan.getExpression(), + new CompositeLocation(), constraint, isLHS); + // addTypeLocation(aan.getExpression().getType(), arrayLoc); CompositeLocation indexLoc = - checkLocationFromExpressionNode(md, nametable, aan.getIndex(), new CompositeLocation()); - glbInputSet.add(indexLoc); - addTypeLocation(aan.getIndex().getType(), indexLoc); + checkLocationFromExpressionNode(md, nametable, aan.getIndex(), new CompositeLocation(), + constraint, isLHS); + // addTypeLocation(aan.getIndex().getType(), indexLoc); + + if (isLHS) { + if (!CompositeLattice.isGreaterThan(indexLoc, arrayLoc, generateErrorMessage(cd, aan))) { + throw new Error("Array index value is not higher than array location at " + + generateErrorMessage(cd, aan)); + } + return arrayLoc; + } else { + Set inputGLB = new HashSet(); + inputGLB.add(arrayLoc); + inputGLB.add(indexLoc); + return CompositeLattice.calculateGLB(inputGLB, generateErrorMessage(cd, aan)); + } - CompositeLocation glbLoc = CompositeLattice.calculateGLB(glbInputSet); - return glbLoc; } private CompositeLocation checkLocationFromCreateObjectNode(MethodDescriptor md, @@ -674,26 +1102,6 @@ public class FlowDownCheck { ClassDescriptor cd = md.getClassDesc(); - // check arguments - Set glbInputSet = new HashSet(); - for (int i = 0; i < con.numArgs(); i++) { - ExpressionNode en = con.getArg(i); - CompositeLocation argLoc = - checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation()); - glbInputSet.add(argLoc); - addTypeLocation(en.getType(), argLoc); - } - - // check array initializers - // if ((con.getArrayInitializer() != null)) { - // checkLocationFromArrayInitializerNode(md, nametable, - // con.getArrayInitializer()); - // } - - if (glbInputSet.size() > 0) { - return CompositeLattice.calculateGLB(glbInputSet); - } - CompositeLocation compLoc = new CompositeLocation(); compLoc.addLocation(Location.createTopLocation(md)); return compLoc; @@ -701,24 +1109,26 @@ public class FlowDownCheck { } private CompositeLocation checkLocationFromOpNode(MethodDescriptor md, SymbolTable nametable, - OpNode on) { + OpNode on, CompositeLocation constraint) { ClassDescriptor cd = md.getClassDesc(); CompositeLocation leftLoc = new CompositeLocation(); - leftLoc = checkLocationFromExpressionNode(md, nametable, on.getLeft(), leftLoc); + leftLoc = + checkLocationFromExpressionNode(md, nametable, on.getLeft(), leftLoc, constraint, false); // addTypeLocation(on.getLeft().getType(), leftLoc); CompositeLocation rightLoc = new CompositeLocation(); if (on.getRight() != null) { - rightLoc = checkLocationFromExpressionNode(md, nametable, on.getRight(), rightLoc); + rightLoc = + checkLocationFromExpressionNode(md, nametable, on.getRight(), rightLoc, constraint, false); // addTypeLocation(on.getRight().getType(), rightLoc); } - // System.out.println("checking op node=" + on.printNode(0)); - // System.out.println("left loc=" + leftLoc + " from " + - // on.getLeft().getClass()); - // System.out.println("right loc=" + rightLoc + " from " + - // on.getRight().getClass()); + System.out.println("\n# OP NODE=" + on.printNode(0)); + System.out.println("# left loc=" + leftLoc + " from " + on.getLeft().getClass()); + if (on.getRight() != null) { + System.out.println("# right loc=" + rightLoc + " from " + on.getRight().getClass()); + } Operation op = on.getOp(); @@ -755,7 +1165,9 @@ public class FlowDownCheck { Set inputSet = new HashSet(); inputSet.add(leftLoc); inputSet.add(rightLoc); - CompositeLocation glbCompLoc = CompositeLattice.calculateGLB(inputSet); + CompositeLocation glbCompLoc = + CompositeLattice.calculateGLB(inputSet, generateErrorMessage(cd, on)); + System.out.println("# glbCompLoc=" + glbCompLoc); return glbCompLoc; default: @@ -776,22 +1188,28 @@ public class FlowDownCheck { } private CompositeLocation checkLocationFromNameNode(MethodDescriptor md, SymbolTable nametable, - NameNode nn, CompositeLocation loc) { + NameNode nn, CompositeLocation loc, CompositeLocation constraint) { NameDescriptor nd = nn.getName(); if (nd.getBase() != null) { - loc = checkLocationFromExpressionNode(md, nametable, nn.getExpression(), loc); - // addTypeLocation(nn.getExpression().getType(), loc); + loc = + checkLocationFromExpressionNode(md, nametable, nn.getExpression(), loc, constraint, false); } else { String varname = nd.toString(); - if (varname.equals("this")) { // 'this' itself! MethodLattice methodLattice = ssjava.getMethodLattice(md); - Location locElement = new Location(md, methodLattice.getThisLoc()); + String thisLocId = methodLattice.getThisLoc(); + if (thisLocId == null) { + throw new Error("The location for 'this' is not defined at " + + md.getClassDesc().getSourceFileName() + "::" + nn.getNumLine()); + } + Location locElement = new Location(md, thisLocId); loc.addLocation(locElement); return loc; + } + Descriptor d = (Descriptor) nametable.get(varname); // CompositeLocation localLoc = null; @@ -799,71 +1217,169 @@ public class FlowDownCheck { VarDescriptor vd = (VarDescriptor) d; // localLoc = d2loc.get(vd); // the type of var descriptor has a composite location! - loc = (CompositeLocation) vd.getType().getExtension(); + loc = ((CompositeLocation) vd.getType().getExtension()).clone(); } else if (d instanceof FieldDescriptor) { // the type of field descriptor has a location! FieldDescriptor fd = (FieldDescriptor) d; + if (fd.isStatic()) { + if (fd.isFinal()) { + // if it is 'static final', the location has TOP since no one can + // change its value + loc.addLocation(Location.createTopLocation(md)); + return loc; + } else { + // if 'static', the location has pre-assigned global loc + MethodLattice localLattice = ssjava.getMethodLattice(md); + String globalLocId = localLattice.getGlobalLoc(); + if (globalLocId == null) { + throw new Error("Global location element is not defined in the method " + md); + } + Location globalLoc = new Location(md, globalLocId); + + loc.addLocation(globalLoc); + } + } else { + // the location of field access starts from this, followed by field + // location + MethodLattice localLattice = ssjava.getMethodLattice(md); + Location thisLoc = new Location(md, localLattice.getThisLoc()); + loc.addLocation(thisLoc); + } - // the location of field access starts from this, followed by field - // location - MethodLattice localLattice = ssjava.getMethodLattice(md); - Location thisLoc = new Location(md, localLattice.getThisLoc()); - loc.addLocation(thisLoc); Location fieldLoc = (Location) fd.getType().getExtension(); loc.addLocation(fieldLoc); + } else if (d == null) { + // access static field + ClassDescriptor cd = nn.getClassDesc(); + + MethodLattice localLattice = ssjava.getMethodLattice(md); + String globalLocId = localLattice.getGlobalLoc(); + if (globalLocId == null) { + throw new Error("Method lattice does not define global variable location at " + + generateErrorMessage(md.getClassDesc(), nn)); + } + loc.addLocation(new Location(md, globalLocId)); + return loc; + } } - return loc; } private CompositeLocation checkLocationFromFieldAccessNode(MethodDescriptor md, - SymbolTable nametable, FieldAccessNode fan, CompositeLocation loc) { + SymbolTable nametable, FieldAccessNode fan, CompositeLocation loc, + CompositeLocation constraint) { ExpressionNode left = fan.getExpression(); - loc = checkLocationFromExpressionNode(md, nametable, left, loc); - // addTypeLocation(left.getType(), loc); + TypeDescriptor ltd = left.getType(); + + FieldDescriptor fd = fan.getField(); + + String varName = null; + if (left.kind() == Kind.NameNode) { + NameDescriptor nd = ((NameNode) left).getName(); + varName = nd.toString(); + } + if (ltd.isClassNameRef() || (varName != null && varName.equals("this"))) { + // using a class name directly or access using this + if (fd.isStatic() && fd.isFinal()) { + loc.addLocation(Location.createTopLocation(md)); + return loc; + } + } + + loc = checkLocationFromExpressionNode(md, nametable, left, loc, constraint, false); if (!left.getType().isPrimitive()) { - FieldDescriptor fd = fan.getField(); - Location fieldLoc = (Location) fd.getType().getExtension(); + Location fieldLoc = getFieldLocation(fd); loc.addLocation(fieldLoc); } return loc; } + private Location getFieldLocation(FieldDescriptor fd) { + + Location fieldLoc = (Location) fd.getType().getExtension(); + + // handle the case that method annotation checking skips checking field + // declaration + if (fieldLoc == null) { + fieldLoc = checkFieldDeclaration(fd.getClassDescriptor(), fd); + } + + return fieldLoc; + + } + private CompositeLocation checkLocationFromAssignmentNode(MethodDescriptor md, - SymbolTable nametable, AssignmentNode an, CompositeLocation loc) { + SymbolTable nametable, AssignmentNode an, CompositeLocation loc, CompositeLocation constraint) { + + System.out.println("\n# ASSIGNMENTNODE=" + an.printNode(0)); ClassDescriptor cd = md.getClassDesc(); + Set inputGLBSet = new HashSet(); + boolean postinc = true; if (an.getOperation().getBaseOp() == null || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation() .getBaseOp().getOp() != Operation.POSTDEC)) postinc = false; + // if LHS is array access node, need to check if array index is higher + // than array itself CompositeLocation destLocation = - checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation()); + checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(), + constraint, true); + + CompositeLocation rhsLocation; + CompositeLocation srcLocation; - CompositeLocation srcLocation = new CompositeLocation(); if (!postinc) { - srcLocation = new CompositeLocation(); - srcLocation = checkLocationFromExpressionNode(md, nametable, an.getSrc(), srcLocation); - // System.out.println("an=" + an.printNode(0) + " an.getSrc()=" + - // an.getSrc().getClass() - // + " at " + cd.getSourceFileName() + "::" + an.getNumLine()); - if (!CompositeLattice.isGreaterThan(srcLocation, destLocation)) { + rhsLocation = + checkLocationFromExpressionNode(md, nametable, an.getSrc(), new CompositeLocation(), + constraint, false); + + System.out.println("dstLocation=" + destLocation); + System.out.println("rhsLocation=" + rhsLocation); + System.out.println("constraint=" + constraint); + + srcLocation = rhsLocation; + + if (!rhsLocation.get(rhsLocation.getSize() - 1).isTop()) { + if (constraint != null) { + inputGLBSet.add(rhsLocation); + inputGLBSet.add(constraint); + srcLocation = CompositeLattice.calculateGLB(inputGLBSet, generateErrorMessage(cd, an)); + } + } + + if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) { throw new Error("The value flow from " + srcLocation + " to " + destLocation + " does not respect location hierarchy on the assignment " + an.printNode(0) + " at " + cd.getSourceFileName() + "::" + an.getNumLine()); } + } else { destLocation = - srcLocation = checkLocationFromExpressionNode(md, nametable, an.getDest(), srcLocation); + rhsLocation = + checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation(), + constraint, false); + + if (constraint != null) { + inputGLBSet.add(rhsLocation); + inputGLBSet.add(constraint); + srcLocation = CompositeLattice.calculateGLB(inputGLBSet, generateErrorMessage(cd, an)); + } else { + srcLocation = rhsLocation; + } + + System.out.println("srcLocation=" + srcLocation); + System.out.println("rhsLocation=" + rhsLocation); + System.out.println("constraint=" + constraint); - if (!CompositeLattice.isGreaterThan(srcLocation, destLocation)) { + if (!CompositeLattice.isGreaterThan(srcLocation, destLocation, generateErrorMessage(cd, an))) { throw new Error("Location " + destLocation + " is not allowed to have the value flow that moves within the same location at " + cd.getSourceFileName() + "::" + an.getNumLine()); @@ -900,11 +1416,17 @@ public class FlowDownCheck { if (locDec.startsWith(SSJavaAnalysis.DELTA)) { DeltaLocation deltaLoc = parseDeltaDeclaration(md, n, locDec); d2loc.put(vd, deltaLoc); - addTypeLocation(vd.getType(), deltaLoc); + addLocationType(vd.getType(), deltaLoc); } else { CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec); + + Location lastElement = compLoc.get(compLoc.getSize() - 1); + if (ssjava.isSharedLocation(lastElement)) { + ssjava.mapSharedLocation2Descriptor(lastElement, vd); + } + d2loc.put(vd, compLoc); - addTypeLocation(vd.getType(), compLoc); + addLocationType(vd.getType(), compLoc); } } @@ -929,6 +1451,34 @@ public class FlowDownCheck { return deltaLoc; } + private Location parseFieldLocDeclaraton(String decl, String msg) throws Exception { + + int idx = decl.indexOf("."); + + String className = decl.substring(0, idx); + String fieldName = decl.substring(idx + 1); + + className.replaceAll(" ", ""); + fieldName.replaceAll(" ", ""); + + Descriptor d = state.getClassSymbolTable().get(className); + + if (d == null) { + System.out.println("state.getClassSymbolTable()=" + state.getClassSymbolTable()); + throw new Error("The class in the location declaration '" + decl + "' does not exist at " + + msg); + } + + assert (d instanceof ClassDescriptor); + SSJavaLattice lattice = ssjava.getClassLattice((ClassDescriptor) d); + if (!lattice.containsKey(fieldName)) { + throw new Error("The location " + fieldName + " is not defined in the field lattice of '" + + className + "' at " + msg); + } + + return new Location(d, fieldName); + } + private CompositeLocation parseLocationDeclaration(MethodDescriptor md, TreeNode n, String locDec) { CompositeLocation compLoc = new CompositeLocation(); @@ -950,25 +1500,23 @@ public class FlowDownCheck { SSJavaLattice localLattice = CompositeLattice.getLatticeByDescriptor(md); Location localLoc = new Location(md, localLocId); if (localLattice == null || (!localLattice.containsKey(localLocId))) { + System.out.println("locDec=" + locDec); throw new Error("Location " + localLocId + " is not defined in the local variable lattice at " - + md.getClassDesc().getSourceFileName() + "::" + n.getNumLine() + "."); + + md.getClassDesc().getSourceFileName() + "::" + (n != null ? n.getNumLine() : md) + "."); } compLoc.addLocation(localLoc); for (int i = 1; i < locIdList.size(); i++) { String locName = locIdList.get(i); - ClassDescriptor cd = fieldLocName2cd.get(locName); - - SSJavaLattice fieldLattice = CompositeLattice.getLatticeByDescriptor(cd); - - if (fieldLattice == null || (!fieldLattice.containsKey(locName))) { - throw new Error("Location " + locName + " is not defined in the field lattice at " - + cd.getSourceFileName() + "."); + try { + Location fieldLoc = + parseFieldLocDeclaraton(locName, generateErrorMessage(md.getClassDesc(), n)); + compLoc.addLocation(fieldLoc); + } catch (Exception e) { + throw new Error("The location declaration '" + locName + "' is wrong at " + + generateErrorMessage(md.getClassDesc(), n)); } - - Location fieldLoc = new Location(cd, locName); - compLoc.addLocation(fieldLoc); } return compLoc; @@ -980,34 +1528,29 @@ public class FlowDownCheck { assignLocationOfVarDescriptor(vd, md, nametable, dn); } - private void checkClass(ClassDescriptor cd) { - // Check to see that methods respects ss property - for (Iterator method_it = cd.getMethods(); method_it.hasNext();) { - MethodDescriptor md = (MethodDescriptor) method_it.next(); - checkMethodDeclaration(cd, md); - } - } - private void checkDeclarationInClass(ClassDescriptor cd) { // Check to see that fields are okay for (Iterator field_it = cd.getFields(); field_it.hasNext();) { FieldDescriptor fd = (FieldDescriptor) field_it.next(); - checkFieldDeclaration(cd, fd); - } - } - private void checkMethodDeclaration(ClassDescriptor cd, MethodDescriptor md) { - // TODO + if (!(fd.isFinal() && fd.isStatic())) { + checkFieldDeclaration(cd, fd); + } else { + // for static final, assign top location by default + Location loc = Location.createTopLocation(cd); + addLocationType(fd.getType(), loc); + } + } } - private void checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) { + private Location checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) { Vector annotationVec = fd.getType().getAnnotationMarkers(); // currently enforce every field to have corresponding location if (annotationVec.size() == 0) { - throw new Error("Location is not assigned to the field " + fd.getSymbol() + " of the class " - + cd.getSymbol()); + throw new Error("Location is not assigned to the field '" + fd.getSymbol() + + "' of the class " + cd.getSymbol() + " at " + cd.getSourceFileName()); } if (annotationVec.size() > 1) { @@ -1017,9 +1560,9 @@ public class FlowDownCheck { } AnnotationDescriptor ad = annotationVec.elementAt(0); + Location loc = null; if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) { - if (ad.getMarker().equals(SSJavaAnalysis.LOC)) { String locationID = ad.getValue(); // check if location is defined @@ -1029,22 +1572,27 @@ public class FlowDownCheck { + " is not defined in the field lattice of class " + cd.getSymbol() + " at" + cd.getSourceFileName() + "."); } - Location loc = new Location(cd, locationID); - // d2loc.put(fd, loc); - addTypeLocation(fd.getType(), loc); + loc = new Location(cd, locationID); + + if (ssjava.isSharedLocation(loc)) { + ssjava.mapSharedLocation2Descriptor(loc, fd); + } + + addLocationType(fd.getType(), loc); } } + return loc; } - private void addTypeLocation(TypeDescriptor type, CompositeLocation loc) { + private void addLocationType(TypeDescriptor type, CompositeLocation loc) { if (type != null) { type.setExtension(loc); } } - private void addTypeLocation(TypeDescriptor type, Location loc) { + private void addLocationType(TypeDescriptor type, Location loc) { if (type != null) { type.setExtension(loc); } @@ -1052,9 +1600,10 @@ public class FlowDownCheck { static class CompositeLattice { - public static boolean isGreaterThan(CompositeLocation loc1, CompositeLocation loc2) { + public static boolean isGreaterThan(CompositeLocation loc1, CompositeLocation loc2, String msg) { - int baseCompareResult = compareBaseLocationSet(loc1, loc2); + System.out.println("\nisGreaterThan=" + loc1 + " " + loc2 + " msg=" + msg); + int baseCompareResult = compareBaseLocationSet(loc1, loc2, true, false, msg); if (baseCompareResult == ComparisonResult.EQUAL) { if (compareDelta(loc1, loc2) == ComparisonResult.GREATER) { return true; @@ -1069,6 +1618,20 @@ public class FlowDownCheck { } + public static int compare(CompositeLocation loc1, CompositeLocation loc2, boolean ignore, + String msg) { + + System.out.println("compare=" + loc1 + " " + loc2); + int baseCompareResult = compareBaseLocationSet(loc1, loc2, false, ignore, msg); + + if (baseCompareResult == ComparisonResult.EQUAL) { + return compareDelta(loc1, loc2); + } else { + return baseCompareResult; + } + + } + private static int compareDelta(CompositeLocation dLoc1, CompositeLocation dLoc2) { int deltaCount1 = 0; @@ -1090,7 +1653,8 @@ public class FlowDownCheck { } - private static int compareBaseLocationSet(CompositeLocation compLoc1, CompositeLocation compLoc2) { + private static int compareBaseLocationSet(CompositeLocation compLoc1, + CompositeLocation compLoc2, boolean awareSharedLoc, boolean ignore, String msg) { // if compLoc1 is greater than compLoc2, return true // else return false; @@ -1100,35 +1664,51 @@ public class FlowDownCheck { for (int i = 0; i < compLoc1.getSize(); i++) { Location loc1 = compLoc1.get(i); if (i >= compLoc2.getSize()) { - throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 - + " because they are not comparable."); + if (ignore) { + return ComparisonResult.INCOMPARABLE; + } else { + throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 + + " because they are not comparable at " + msg); + } } Location loc2 = compLoc2.get(i); - if (!loc1.getDescriptor().equals(loc2.getDescriptor())) { - throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 - + " because they are not comparable."); - } - - Descriptor d1 = loc1.getDescriptor(); - Descriptor d2 = loc2.getDescriptor(); + Descriptor descriptor = getCommonParentDescriptor(loc1, loc2, msg); + SSJavaLattice lattice = getLatticeByDescriptor(descriptor); - SSJavaLattice lattice1 = getLatticeByDescriptor(d1); - SSJavaLattice lattice2 = getLatticeByDescriptor(d2); + // check if the shared location is appeared only at the end of the + // composite location + if (lattice.getSharedLocSet().contains(loc1.getLocIdentifier())) { + if (i != (compLoc1.getSize() - 1)) { + throw new Error("The shared location " + loc1.getLocIdentifier() + + " cannot be appeared in the middle of composite location at" + msg); + } + } - if (!lattice1.equals(lattice2)) { - throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 - + " because they are not comparable."); + if (lattice.getSharedLocSet().contains(loc2.getLocIdentifier())) { + if (i != (compLoc2.getSize() - 1)) { + throw new Error("The shared location " + loc2.getLocIdentifier() + + " cannot be appeared in the middle of composite location at " + msg); + } } + // if (!lattice1.equals(lattice2)) { + // throw new Error("Failed to compare two locations of " + compLoc1 + + // " and " + compLoc2 + // + " because they are not comparable at " + msg); + // } + if (loc1.getLocIdentifier().equals(loc2.getLocIdentifier())) { + numOfTie++; // check if the current location is the spinning location - if (lattice1.getSpinLocSet().contains(loc1.getLocIdentifier())) { + // note that the spinning location only can be appeared in the last + // part of the composite location + if (awareSharedLoc && numOfTie == compLoc1.getSize() + && lattice.getSharedLocSet().contains(loc1.getLocIdentifier())) { return ComparisonResult.GREATER; } - numOfTie++; continue; - } else if (lattice1.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) { + } else if (lattice.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) { return ComparisonResult.GREATER; } else { return ComparisonResult.LESS; @@ -1139,8 +1719,14 @@ public class FlowDownCheck { if (numOfTie == compLoc1.getSize()) { if (numOfTie != compLoc2.getSize()) { - throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 - + " because they are not comparable."); + + if (ignore) { + return ComparisonResult.INCOMPARABLE; + } else { + throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2 + + " because they are not comparable at " + msg); + } + } return ComparisonResult.EQUAL; @@ -1150,9 +1736,9 @@ public class FlowDownCheck { } - public static CompositeLocation calculateGLB(Set inputSet) { + public static CompositeLocation calculateGLB(Set inputSet, String errMsg) { - // System.out.println("Calculating GLB=" + inputSet); + System.out.println("Calculating GLB=" + inputSet); CompositeLocation glbCompLoc = new CompositeLocation(); // calculate GLB of the first(priority) element @@ -1164,13 +1750,21 @@ public class FlowDownCheck { // mapping from the priority loc ID to its full representation by the // composite location + int maxTupleSize = 0; + CompositeLocation maxCompLoc = null; + + Location prevPriorityLoc = null; for (Iterator iterator = inputSet.iterator(); iterator.hasNext();) { CompositeLocation compLoc = (CompositeLocation) iterator.next(); + if (compLoc.getSize() > maxTupleSize) { + maxTupleSize = compLoc.getSize(); + maxCompLoc = compLoc; + } Location priorityLoc = compLoc.get(0); String priorityLocId = priorityLoc.getLocIdentifier(); priorityLocIdentifierSet.add(priorityLocId); - if (locId2CompLocSet.contains(priorityLocId)) { + if (locId2CompLocSet.containsKey(priorityLocId)) { locId2CompLocSet.get(priorityLocId).add(compLoc); } else { Set newSet = new HashSet(); @@ -1181,59 +1775,102 @@ public class FlowDownCheck { // check if priority location are coming from the same lattice if (priorityDescriptor == null) { priorityDescriptor = priorityLoc.getDescriptor(); - } else if (!priorityDescriptor.equals(priorityLoc.getDescriptor())) { - throw new Error("Failed to calculate GLB of " + inputSet - + " because they are from different lattices."); + } else { + priorityDescriptor = getCommonParentDescriptor(priorityLoc, prevPriorityLoc, errMsg); } + prevPriorityLoc = priorityLoc; + // else if (!priorityDescriptor.equals(priorityLoc.getDescriptor())) { + // throw new Error("Failed to calculate GLB of " + inputSet + // + " because they are from different lattices."); + // } } SSJavaLattice locOrder = getLatticeByDescriptor(priorityDescriptor); String glbOfPriorityLoc = locOrder.getGLB(priorityLocIdentifierSet); glbCompLoc.addLocation(new Location(priorityDescriptor, glbOfPriorityLoc)); - Set compSet = locId2CompLocSet.get(glbOfPriorityLoc); - if (compSet.size() == 1) { - // if GLB(x1,x2)==x1 or x2 : GLB case 2,3 - CompositeLocation comp = compSet.iterator().next(); - for (int i = 1; i < comp.getSize(); i++) { - glbCompLoc.addLocation(comp.get(i)); - } - } else if (compSet.size() == 0) { + if (compSet == null) { // when GLB(x1,x2)!=x1 and !=x2 : GLB case 4 // mean that the result is already lower than and // assign TOP to the rest of the location elements - CompositeLocation inputComp = inputSet.iterator().next(); - for (int i = 1; i < inputComp.getSize(); i++) { - glbCompLoc.addLocation(Location.createTopLocation(inputComp.get(i).getDescriptor())); + + // in this case, do not take care about delta + // CompositeLocation inputComp = inputSet.iterator().next(); + for (int i = 1; i < maxTupleSize; i++) { + glbCompLoc.addLocation(Location.createTopLocation(maxCompLoc.get(i).getDescriptor())); } } else { - // when GLB(x1,x2)==x1 and x2 : GLB case 1 - // if more than one location shares the same priority GLB - // need to calculate the rest of GLB loc - int compositeLocSize = compSet.iterator().next().getSize(); + // here find out composite location that has a maximum length tuple + // if we have three input set: [A], [A,B], [A,B,C] + // maximum length tuple will be [A,B,C] + int max = 0; + CompositeLocation maxFromCompSet = null; + for (Iterator iterator = compSet.iterator(); iterator.hasNext();) { + CompositeLocation c = (CompositeLocation) iterator.next(); + if (c.getSize() > max) { + max = c.getSize(); + maxFromCompSet = c; + } + } + + if (compSet.size() == 1) { + // if GLB(x1,x2)==x1 or x2 : GLB case 2,3 + CompositeLocation comp = compSet.iterator().next(); + for (int i = 1; i < comp.getSize(); i++) { + glbCompLoc.addLocation(comp.get(i)); + } + + // if input location corresponding to glb is a delta, need to apply + // delta to glb result + if (comp instanceof DeltaLocation) { + glbCompLoc = new DeltaLocation(glbCompLoc, 1); + } + + } else { + // when GLB(x1,x2)==x1 and x2 : GLB case 1 + // if more than one location shares the same priority GLB + // need to calculate the rest of GLB loc - Set glbInputSet = new HashSet(); - Descriptor currentD = null; - for (int i = 1; i < compositeLocSize; i++) { + // setup input set starting from the second tuple item + Set innerGLBInput = new HashSet(); for (Iterator iterator = compSet.iterator(); iterator.hasNext();) { - CompositeLocation compositeLocation = (CompositeLocation) iterator.next(); - Location currentLoc = compositeLocation.get(i); - currentD = currentLoc.getDescriptor(); - // making set of the current location sharing the same idx - glbInputSet.add(currentLoc.getLocIdentifier()); + CompositeLocation compLoc = (CompositeLocation) iterator.next(); + CompositeLocation innerCompLoc = new CompositeLocation(); + for (int idx = 1; idx < compLoc.getSize(); idx++) { + innerCompLoc.addLocation(compLoc.get(idx)); + } + if (innerCompLoc.getSize() > 0) { + innerGLBInput.add(innerCompLoc); + } } - // calculate glb for the current lattice - SSJavaLattice currentLattice = getLatticeByDescriptor(currentD); - String currentGLBLocId = currentLattice.getGLB(glbInputSet); - glbCompLoc.addLocation(new Location(currentD, currentGLBLocId)); - } + if (innerGLBInput.size() > 0) { + CompositeLocation innerGLB = CompositeLattice.calculateGLB(innerGLBInput, errMsg); + for (int idx = 0; idx < innerGLB.getSize(); idx++) { + glbCompLoc.addLocation(innerGLB.get(idx)); + } + } + + // if input location corresponding to glb is a delta, need to apply + // delta to glb result + for (Iterator iterator = compSet.iterator(); iterator.hasNext();) { + CompositeLocation compLoc = (CompositeLocation) iterator.next(); + if (compLoc instanceof DeltaLocation) { + if (glbCompLoc.equals(compLoc)) { + glbCompLoc = new DeltaLocation(glbCompLoc, 1); + break; + } + } + } + + } } + System.out.println("GLB=" + glbCompLoc); return glbCompLoc; } @@ -1256,6 +1893,77 @@ public class FlowDownCheck { return lattice; } + static Descriptor getCommonParentDescriptor(Location loc1, Location loc2, String msg) { + + Descriptor d1 = loc1.getDescriptor(); + Descriptor d2 = loc2.getDescriptor(); + + Descriptor descriptor; + + if (d1 instanceof ClassDescriptor && d2 instanceof ClassDescriptor) { + + if (d1.equals(d2)) { + descriptor = d1; + } else { + // identifying which one is parent class + Set d1SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d1); + Set d2SubClassesSet = ssjava.tu.getSubClasses((ClassDescriptor) d2); + + if (d1 == null && d2 == null) { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } else if (d1SubClassesSet != null && d1SubClassesSet.contains(d2)) { + descriptor = d1; + } else if (d2SubClassesSet != null && d2SubClassesSet.contains(d1)) { + descriptor = d2; + } else { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } + } + + } else if (d1 instanceof MethodDescriptor && d2 instanceof MethodDescriptor) { + + if (d1.equals(d2)) { + descriptor = d1; + } else { + + // identifying which one is parent class + MethodDescriptor md1 = (MethodDescriptor) d1; + MethodDescriptor md2 = (MethodDescriptor) d2; + + if (!md1.matches(md2)) { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } + + Set d1SubClassesSet = + ssjava.tu.getSubClasses(((MethodDescriptor) d1).getClassDesc()); + Set d2SubClassesSet = + ssjava.tu.getSubClasses(((MethodDescriptor) d2).getClassDesc()); + + if (d1 == null && d2 == null) { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } else if (d1 != null && d1SubClassesSet.contains(d2)) { + descriptor = d1; + } else if (d2 != null && d2SubClassesSet.contains(d1)) { + descriptor = d2; + } else { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } + } + + } else { + throw new Error("Failed to compare two locations of " + loc1 + " and " + loc2 + + " because they are not comparable at " + msg); + } + + return descriptor; + + } + } class ComparisonResult { @@ -1263,8 +1971,90 @@ public class FlowDownCheck { public static final int GREATER = 0; public static final int EQUAL = 1; public static final int LESS = 2; + public static final int INCOMPARABLE = 3; int result; } } + +class ReturnLocGenerator { + + public static final int PARAMISHIGHER = 0; + public static final int PARAMISSAME = 1; + public static final int IGNORE = 2; + + private Hashtable paramIdx2paramType; + + private CompositeLocation declaredReturnLoc = null; + + public ReturnLocGenerator(CompositeLocation returnLoc, MethodDescriptor md, + List params, String msg) { + + CompositeLocation thisLoc = params.get(0); + if (returnLoc.get(0).equals(thisLoc.get(0)) && returnLoc.getSize() > 1) { + // if the declared return location consists of THIS and field location, + // return location for the caller's side has to have same field element + this.declaredReturnLoc = returnLoc; + } else { + // creating mappings + paramIdx2paramType = new Hashtable(); + for (int i = 0; i < params.size(); i++) { + CompositeLocation param = params.get(i); + int compareResult = CompositeLattice.compare(param, returnLoc, true, msg); + + int type; + if (compareResult == ComparisonResult.GREATER) { + type = 0; + } else if (compareResult == ComparisonResult.EQUAL) { + type = 1; + } else { + type = 2; + } + paramIdx2paramType.put(new Integer(i), new Integer(type)); + } + } + + } + + public CompositeLocation computeReturnLocation(List args) { + + if (declaredReturnLoc != null) { + // when developer specify that the return value is [THIS,field] + // needs to translate to the caller's location + CompositeLocation callerLoc = new CompositeLocation(); + CompositeLocation callerBaseLocation = args.get(0); + + for (int i = 0; i < callerBaseLocation.getSize(); i++) { + callerLoc.addLocation(callerBaseLocation.get(i)); + } + for (int i = 1; i < declaredReturnLoc.getSize(); i++) { + callerLoc.addLocation(declaredReturnLoc.get(i)); + } + return callerLoc; + } else { + // compute the highest possible location in caller's side + assert paramIdx2paramType.keySet().size() == args.size(); + + Set inputGLB = new HashSet(); + for (int i = 0; i < args.size(); i++) { + int type = (paramIdx2paramType.get(new Integer(i))).intValue(); + CompositeLocation argLoc = args.get(i); + if (type == PARAMISHIGHER) { + // return loc is lower than param + DeltaLocation delta = new DeltaLocation(argLoc, 1); + inputGLB.add(delta); + } else if (type == PARAMISSAME) { + // return loc is equal or lower than param + inputGLB.add(argLoc); + } + } + + // compute GLB of arguments subset that are same or higher than return + // location + CompositeLocation glb = CompositeLattice.calculateGLB(inputGLB, ""); + return glb; + } + + } +}