+ private CompositeLocation checkLocationFromCastNode(MethodDescriptor md, SymbolTable nametable,
+ CastNode cn, CompositeLocation constraint) {
+
+ ExpressionNode en = cn.getExpression();
+ return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+
+ }
+
+ private CompositeLocation checkLocationFromTertiaryNode(MethodDescriptor md,
+ SymbolTable nametable, TertiaryNode tn, CompositeLocation constraint) {
+ ClassDescriptor cd = md.getClassDesc();
+
+ CompositeLocation condLoc =
+ checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation(),
+ constraint, false);
+ // addLocationType(tn.getCond().getType(), condLoc);
+ CompositeLocation trueLoc =
+ checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation(),
+ constraint, false);
+ // addLocationType(tn.getTrueExpr().getType(), trueLoc);
+ CompositeLocation 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!
+
+ // System.out.println("\n#tertiary cond=" + tn.getCond().printNode(0) +
+ // " Loc=" + condLoc);
+ // System.out.println("# true=" + tn.getTrueExpr().printNode(0) + " Loc=" +
+ // trueLoc);
+ // System.out.println("# false=" + tn.getFalseExpr().printNode(0) + " Loc="
+ // + falseLoc);
+
+ // check if condLoc is higher than trueLoc & falseLoc
+ 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 (!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 false expression at "
+ + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
+ }
+
+ // then, return glb of trueLoc & falseLoc
+ Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
+ glbInputSet.add(trueLoc);
+ glbInputSet.add(falseLoc);
+
+ if (glbInputSet.size() == 1) {
+ return trueLoc;
+ } else {
+ return CompositeLattice.calculateGLB(glbInputSet, generateErrorMessage(cd, tn));
+ }
+
+ }
+
+ private CompositeLocation checkLocationFromMethodInvokeNode(MethodDescriptor md,
+ SymbolTable nametable, MethodInvokeNode min, CompositeLocation loc,
+ CompositeLocation constraint) {
+
+ ClassDescriptor cd = md.getClassDesc();
+ MethodDescriptor calleeMethodDesc = min.getMethod();
+
+ NameDescriptor baseName = min.getBaseName();
+ boolean isSystemout = false;
+ if (baseName != null) {
+ isSystemout = baseName.getSymbol().equals("System.out");
+ }
+
+ if (!ssjava.isSSJavaUtil(calleeMethodDesc.getClassDesc())
+ && !ssjava.isTrustMethod(calleeMethodDesc) && !calleeMethodDesc.getModifiers().isNative()
+ && !isSystemout) {
+
+ 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));
+ }
+ }
+
+ // System.out.println("\n#checkLocationFromMethodInvokeNode=" +
+ // min.printNode(0)
+ // + " baseLocation=" + baseLocation + " constraint=" + constraint);
+
+ // setup the location list of caller's arguments
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+
+ // setup the location list of callee's parameters
+ MethodLattice<String> calleeLattice = ssjava.getMethodLattice(calleeMethodDesc);
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ if (min.numArgs() > 0) {
+ if (!calleeMethodDesc.isStatic()) {
+ callerArgList.add(baseLocation);
+ }
+ 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);
+ }
+
+ if (!calleeMethodDesc.isStatic()) {
+ CompositeLocation calleeThisLoc =
+ new CompositeLocation(new Location(calleeMethodDesc, calleeLattice.getThisLoc()));
+ calleeParamList.add(calleeThisLoc);
+ }
+
+ for (int i = 0; i < calleeMethodDesc.numParameters(); i++) {
+ VarDescriptor calleevd = (VarDescriptor) calleeMethodDesc.getParameter(i);
+ CompositeLocation calleeLoc = d2loc.get(calleevd);
+ calleeParamList.add(calleeLoc);
+ }
+ }
+
+ if (constraint != null) {
+ // check whether the PC location is lower than one of the
+ // argument locations. If it is lower, the callee has to have @PCLOC
+ // annotation that declares the program counter that is higher than
+ // corresponding parameter
+
+ CompositeLocation calleePCLOC = ssjava.getPCLocation(calleeMethodDesc);
+
+ for (int idx = 0; idx < callerArgList.size(); idx++) {
+ CompositeLocation argLocation = callerArgList.get(idx);
+
+ // need to check that param is higher than PCLOC
+ if (!argLocation.get(0).isTop()
+ && CompositeLattice.compare(argLocation, constraint, true,
+ generateErrorMessage(cd, min)) == ComparisonResult.GREATER) {
+
+ CompositeLocation paramLocation = calleeParamList.get(idx);
+
+ int paramCompareResult =
+ CompositeLattice.compare(calleePCLOC, paramLocation, true,
+ generateErrorMessage(cd, min));
+
+ if (paramCompareResult == ComparisonResult.GREATER) {
+ throw new Error(
+ "The program counter location "
+ + constraint
+ + " is lower than the argument(idx="
+ + idx
+ + ") location "
+ + argLocation
+ + ". Need to specify that the initial PC location of the callee, which is currently set to "
+ + calleePCLOC + ", is lower than " + paramLocation + " in the method "
+ + calleeMethodDesc.getSymbol() + ":" + min.getNumLine());
+ }
+
+ }
+
+ }
+
+ }
+
+ checkCalleeConstraints(md, nametable, min, baseLocation, constraint);
+
+ // checkCallerArgumentLocationConstraints(md, nametable, min,
+ // baseLocation, constraint);
+
+ 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;
+ }
+ }
+
+ return new CompositeLocation(Location.createTopLocation(md));
+
+ }
+
+ private CompositeLocation translateCallerLocToCalleeLoc(MethodDescriptor calleeMD,
+ CompositeLocation calleeBaseLoc, CompositeLocation constraint) {
+
+ CompositeLocation calleeConstraint = new CompositeLocation();
+
+ // if (constraint.startsWith(calleeBaseLoc)) {
+ // if the first part of constraint loc is matched with callee base loc
+ Location thisLoc = new Location(calleeMD, ssjava.getMethodLattice(calleeMD).getThisLoc());
+ calleeConstraint.addLocation(thisLoc);
+ for (int i = calleeBaseLoc.getSize(); i < constraint.getSize(); i++) {
+ calleeConstraint.addLocation(constraint.get(i));
+ }
+
+ // }
+
+ return calleeConstraint;
+ }
+
+ private void checkCallerArgumentLocationConstraints(MethodDescriptor md, SymbolTable nametable,
+ MethodInvokeNode min, CompositeLocation callerBaseLoc, 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.
+
+ MethodDescriptor calleemd = min.getMethod();
+
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ MethodLattice<String> 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);
+
+ // System.out.println("checkCallerArgumentLocationConstraints=" +
+ // min.printNode(0));
+ // System.out.println("base location=" + callerBaseLoc + " constraint=" +
+ // constraint);
+
+ 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 callerArgLoc = callerArgList.get(i);
+
+ CompositeLocation paramLocation =
+ translateCalleeParamLocToCaller(md, calleeParamLoc, callerBaseLoc, errorMsg);
+
+ Set<CompositeLocation> inputGLBSet = new HashSet<CompositeLocation>();
+ if (constraint != null) {
+ inputGLBSet.add(callerArgLoc);
+ inputGLBSet.add(constraint);
+ callerArgLoc =
+ CompositeLattice.calculateGLB(inputGLBSet,
+ generateErrorMessage(md.getClassDesc(), min));
+ }
+
+ if (!CompositeLattice.isGreaterThan(callerArgLoc, paramLocation, errorMsg)) {
+ throw new Error("Caller argument '" + min.getArg(i).printNode(0) + " : " + callerArgLoc
+ + "' should be higher than corresponding callee's parameter : " + paramLocation
+ + " at " + errorMsg);
+ }
+
+ }
+ }
+
+ }
+
+ private CompositeLocation translateCalleeParamLocToCaller(MethodDescriptor md,
+ CompositeLocation calleeParamLoc, CompositeLocation callerBaseLocation, String errorMsg) {
+
+ CompositeLocation translate = new CompositeLocation();
+
+ for (int i = 0; i < callerBaseLocation.getSize(); i++) {
+ translate.addLocation(callerBaseLocation.get(i));
+ }
+
+ for (int i = 1; i < calleeParamLoc.getSize(); i++) {
+ translate.addLocation(calleeParamLoc.get(i));
+ }
+
+ // System.out.println("TRANSLATED=" + translate + " from calleeParamLoc=" +
+ // calleeParamLoc);
+
+ return translate;
+ }
+
+ private CompositeLocation computeCeilingLocationForCaller(MethodDescriptor md,
+ SymbolTable nametable, MethodInvokeNode min, CompositeLocation baseLocation,
+ CompositeLocation constraint) {
+ List<CompositeLocation> argList = new ArrayList<CompositeLocation>();
+
+ // by default, method has a THIS parameter
+ argList.add(baseLocation);
+
+ for (int i = 0; i < min.numArgs(); i++) {
+ ExpressionNode en = min.getArg(i);
+ CompositeLocation callerArg =
+ checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation(), constraint,
+ false);
+ argList.add(callerArg);
+ }
+
+ // System.out.println("\n## computeReturnLocation=" + min.getMethod() +
+ // " argList=" + argList);
+ CompositeLocation ceilLoc = md2ReturnLocGen.get(min.getMethod()).computeReturnLocation(argList);
+ // System.out.println("## ReturnLocation=" + ceilLoc);
+
+ return ceilLoc;
+
+ }
+
+ private void checkCalleeConstraints(MethodDescriptor md, SymbolTable nametable,
+ MethodInvokeNode min, CompositeLocation callerBaseLoc, CompositeLocation constraint) {
+
+ MethodDescriptor calleemd = min.getMethod();
+
+ MethodLattice<String> calleeLattice = ssjava.getMethodLattice(calleemd);
+
+ CompositeLocation calleeThisLoc =
+ new CompositeLocation(new Location(calleemd, calleeLattice.getThisLoc()));
+
+ List<CompositeLocation> callerArgList = new ArrayList<CompositeLocation>();
+ List<CompositeLocation> calleeParamList = new ArrayList<CompositeLocation>();
+
+ 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
+ if (!calleemd.isStatic())
+ 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
+ if (!calleemd.isStatic())
+ 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);
+ // System.out.println("calleevd=" + calleevd + " loc=" + calleeLoc);
+ 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;
+ }
+
+ // System.out.println("calleeLoc1=" + calleeLoc1);
+ // System.out.println("calleeLoc2=" + calleeLoc2 +
+ // "calleeParamList=" + calleeParamList);
+
+ int callerResult =
+ CompositeLattice.compare(callerLoc1, callerLoc2, true,
+ generateErrorMessage(md.getClassDesc(), min));
+ // System.out.println("callerResult=" + callerResult);
+ int calleeResult =
+ CompositeLattice.compare(calleeLoc1, calleeLoc2, true,
+ generateErrorMessage(md.getClassDesc(), min));
+ // System.out.println("calleeResult=" + calleeResult);
+
+ if (callerResult == ComparisonResult.EQUAL) {
+ if (ssjava.isSharedLocation(callerLoc1.get(callerLoc1.getSize() - 1))
+ && ssjava.isSharedLocation(callerLoc2.get(callerLoc2.getSize() - 1))) {
+ // if both of them are shared locations, promote them to
+ // "GREATER relation"
+ callerResult = ComparisonResult.GREATER;
+ }
+ }
+
+ 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, CompositeLocation constraint, boolean isLHS) {
+
+ ClassDescriptor cd = md.getClassDesc();