All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.unive.lisa.analysis.heap.pointbased.AllocationSiteBasedAnalysis Maven / Gradle / Ivy

The newest version!
package it.unive.lisa.analysis.heap.pointbased;

import it.unive.lisa.analysis.Lattice;
import it.unive.lisa.analysis.SemanticException;
import it.unive.lisa.analysis.SemanticOracle;
import it.unive.lisa.analysis.heap.BaseHeapDomain;
import it.unive.lisa.analysis.lattices.ExpressionSet;
import it.unive.lisa.analysis.lattices.Satisfiability;
import it.unive.lisa.analysis.nonrelational.heap.HeapEnvironment;
import it.unive.lisa.program.annotations.Annotation;
import it.unive.lisa.program.cfg.CodeLocation;
import it.unive.lisa.program.cfg.ProgramPoint;
import it.unive.lisa.symbolic.SymbolicExpression;
import it.unive.lisa.symbolic.heap.AccessChild;
import it.unive.lisa.symbolic.heap.HeapDereference;
import it.unive.lisa.symbolic.heap.HeapExpression;
import it.unive.lisa.symbolic.heap.HeapReference;
import it.unive.lisa.symbolic.heap.MemoryAllocation;
import it.unive.lisa.symbolic.value.HeapLocation;
import it.unive.lisa.symbolic.value.Identifier;
import it.unive.lisa.symbolic.value.MemoryPointer;
import it.unive.lisa.symbolic.value.PushAny;
import it.unive.lisa.symbolic.value.Variable;
import it.unive.lisa.type.ReferenceType;
import it.unive.lisa.type.Type;
import it.unive.lisa.util.collections.workset.VisitOnceFIFOWorkingSet;
import it.unive.lisa.util.collections.workset.WorkingSet;
import it.unive.lisa.util.representation.StructuredRepresentation;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * A base class for heap analyses based on the allocation sites of the objects
 * and arrays they track, namely the position of the code where heap locations
 * are generated. All heap locations that are generated at the same allocation
 * sites are abstracted into a single unique heap identifier. Concrete instances
 * have control over their field-sensitivity.
 * 
 * @author Luca Negrini
 * 
 * @param  the concrete type of analysis that methods of this class return
 */
public abstract class AllocationSiteBasedAnalysis>
		implements
		BaseHeapDomain {

	/**
	 * An heap environment tracking which allocation sites are associated to
	 * each identifier.
	 */
	public final HeapEnvironment heapEnv;

	/**
	 * The replacements to be applied after the generation of this domain
	 * instance.
	 */
	public final List replacements;

	/**
	 * Builds a new instance of allocation site-based heap.
	 */
	protected AllocationSiteBasedAnalysis() {
		this(new HeapEnvironment<>(new AllocationSites()));
	}

	/**
	 * Builds a new instance of allocation site-based heap from its heap
	 * environment.
	 * 
	 * @param heapEnv the heap environment that this instance tracks
	 */
	public AllocationSiteBasedAnalysis(
			HeapEnvironment heapEnv) {
		this(heapEnv, Collections.emptyList());
	}

	/**
	 * Builds a new instance of allocation site-based heap from its heap
	 * environment and replacements.
	 * 
	 * @param heapEnv      the heap environment that this instance tracks
	 * @param replacements the heap replacements of this instance
	 */
	public AllocationSiteBasedAnalysis(
			HeapEnvironment heapEnv,
			List replacements) {
		this.heapEnv = heapEnv;
		this.replacements = replacements.isEmpty() ? Collections.emptyList() : replacements;
	}

	/**
	 * Builds a new instance of this class by copying abstract information from
	 * {@code reference} and using the given environment for storing points-to
	 * information.
	 * 
	 * @param reference the domain whose abstract information needs to be copied
	 * @param heapEnv   the heap environment that this instance tracks
	 * 
	 * @return the new instance
	 */
	protected abstract A mk(
			A reference,
			HeapEnvironment heapEnv);

	@Override
	public A assign(
			Identifier id,
			SymbolicExpression expression,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		A sss = smallStepSemantics(expression, pp, oracle);
		A result = bottom();
		List replacements = new LinkedList<>();
		ExpressionSet rhsExps;
		if (expression.mightNeedRewriting())
			rhsExps = rewrite(expression, pp, oracle);
		else
			rhsExps = new ExpressionSet(expression);

		for (SymbolicExpression rhs : rhsExps)
			if (rhs instanceof MemoryPointer) {
				HeapLocation rhs_ref = ((MemoryPointer) rhs).getReferencedLocation();
				if (id instanceof MemoryPointer) {
					// we have x = y, where both are pointers we perform *x = *y
					// so that x and y become aliases
					Identifier lhs_ref = ((MemoryPointer) id).getReferencedLocation();
					HeapEnvironment heap = sss.heapEnv.assign(lhs_ref, rhs_ref, pp, oracle);
					result = result.lub(mk(sss, heap));
				} else if (rhs_ref instanceof StackAllocationSite
						&& !getAllocatedAt(((StackAllocationSite) rhs_ref).getLocationName()).isEmpty())
					// for stack elements, assignment works as a shallow copy
					// since there are no pointers to alias
					result = result.lub(sss.shallowCopy(id, (StackAllocationSite) rhs_ref, replacements, pp, oracle));
				else {
					// aliasing: id and star_y points to the same object
					HeapEnvironment heap = sss.heapEnv.assign(id, rhs_ref, pp, oracle);
					result = result.lub(mk(sss, heap));
				}
			} else
				result = result.lub(sss);

		return mk(result, replacements);
	}

	/**
	 * Yields an allocation site name {@code id} if it is tracked by this
	 * domain, {@code null} otherwise.
	 * 
	 * @param location allocation site's name to be searched
	 * 
	 * @return an allocation site name {@code id} if it is tracked by this
	 *             domain, {@code null} otherwise
	 */
	protected Set getAllocatedAt(
			String location) {
		Set sites = new HashSet<>();
		for (AllocationSites set : heapEnv.getValues())
			for (AllocationSite site : set)
				if (site.getLocationName().equals(location))
					sites.add(site);

		return sites;
	}

	/**
	 * Performs the assignment of {@code site} to the identifier {@code id} when
	 * {@code site} is a static allocation site, thus performing a shallow copy
	 * instead of aliasing handling the heap replacements.
	 * 
	 * @param id           the identifier to be updated
	 * @param site         the allocation site to be assigned
	 * @param replacements the list of replacements to be updated
	 * @param pp           the program point where this operation occurs
	 * @param oracle       the oracle for inter-domain communication
	 * 
	 * @return the point-based heap instance where {@code id} is updated with
	 *             {@code star_y} and the needed heap replacements
	 * 
	 * @throws SemanticException if something goes wrong during the analysis
	 */
	@SuppressWarnings("unchecked")
	public A shallowCopy(
			Identifier id,
			StackAllocationSite site,
			List replacements,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		// no aliasing: star_y must be cloned and the clone must
		// be assigned to id
		StackAllocationSite clone = new StackAllocationSite(site.getStaticType(),
				id.getCodeLocation().toString(), site.isWeak(), id.getCodeLocation());
		HeapEnvironment tmp = heapEnv.assign(id, clone, pp, oracle);

		HeapReplacement replacement = new HeapReplacement();
		replacement.addSource(site);
		replacement.addTarget(clone);
		replacement.addTarget(site);
		replacements.add(replacement);

		return mk((A) this, tmp);
	}

	@Override
	public A assume(
			SymbolicExpression expression,
			ProgramPoint src,
			ProgramPoint dest,
			SemanticOracle oracle)
			throws SemanticException {
		// we just rewrite the expression if needed
		return smallStepSemantics(expression, src, oracle);
	}

	@Override
	public Satisfiability satisfies(
			SymbolicExpression expression,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		// we leave the decision to the value domain
		return Satisfiability.UNKNOWN;
	}

	@Override
	public StructuredRepresentation representation() {
		if (isTop())
			return Lattice.topRepresentation();

		if (isBottom())
			return Lattice.bottomRepresentation();

		return heapEnv.representation();
	}

	@Override
	public boolean isTop() {
		return heapEnv.isTop();
	}

	@Override
	public boolean isBottom() {
		return heapEnv.isBottom();
	}

	@Override
	public List getSubstitution() {
		return replacements;
	}

	@Override
	public boolean lessOrEqualAux(
			A other)
			throws SemanticException {
		return heapEnv.lessOrEqual(other.heapEnv);
	}

	@Override
	public int hashCode() {
		return Objects.hash(heapEnv, replacements);
	}

	@Override
	public boolean equals(
			Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		@SuppressWarnings("unchecked")
		A other = (A) obj;
		return Objects.equals(heapEnv, other.heapEnv) && Objects.equals(replacements, other.replacements);
	}

	@Override
	@SuppressWarnings("unchecked")
	public A semanticsOf(
			HeapExpression expression,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		return (A) this;
	}

	@Override
	public ExpressionSet rewrite(
			SymbolicExpression expression,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		return expression.accept(new Rewriter(), pp, oracle);
	}

	/**
	 * A {@link it.unive.lisa.analysis.heap.BaseHeapDomain.Rewriter} for the
	 * {@link AllocationSiteBasedAnalysis} domain.
	 * 
	 * @author Luca Negrini
	 */
	public class Rewriter extends BaseHeapDomain.Rewriter {

		/*
		 * note that all the cases where we are adding a plain expression to the
		 * result set in these methods is because it could have been already
		 * rewritten by other rewrite methods to an allocation site
		 */

		@Override
		public ExpressionSet visit(
				AccessChild expression,
				ExpressionSet receiver,
				ExpressionSet child,
				Object... params)
				throws SemanticException {
			Set result = new HashSet<>();
			for (SymbolicExpression rec : receiver) {
				rec = removeTypingExpressions(rec);
				if (rec instanceof MemoryPointer) {
					MemoryPointer pid = (MemoryPointer) rec;
					AllocationSite site = (AllocationSite) pid.getReferencedLocation();
					AllocationSite e;
					if (site instanceof StackAllocationSite)
						e = new StackAllocationSite(
								expression.getStaticType(),
								site.getLocationName(),
								true,
								expression.getCodeLocation());
					else
						e = new HeapAllocationSite(
								expression.getStaticType(),
								site.getLocationName(),
								true,
								expression.getCodeLocation());

					// propagates the annotations of the child value expression
					// to the newly created allocation site
					for (SymbolicExpression f : child)
						if (f instanceof Identifier)
							for (Annotation ann : e.getAnnotations())
								e.addAnnotation(ann);

					result.add(e);
				} else if (rec instanceof AllocationSite)
					result.add(((AllocationSite) rec).withType(expression.getStaticType()));
			}

			return new ExpressionSet(result);
		}

		@Override
		public ExpressionSet visit(
				MemoryAllocation expression,
				Object... params)
				throws SemanticException {
			AllocationSite id;
			if (expression.isStackAllocation())
				id = new StackAllocationSite(
						expression.getStaticType(),
						expression.getCodeLocation().getCodeLocation(),
						true,
						expression.getCodeLocation());
			else
				id = new HeapAllocationSite(
						expression.getStaticType(),
						expression.getCodeLocation().getCodeLocation(),
						true,
						expression.getCodeLocation());

			// propagates the annotations of expression
			// to the newly created allocation site
			for (Annotation ann : expression.getAnnotations())
				id.addAnnotation(ann);

			return new ExpressionSet(id);
		}

		@Override
		public ExpressionSet visit(
				HeapReference expression,
				ExpressionSet arg,
				Object... params)
				throws SemanticException {
			Set result = new HashSet<>();

			for (SymbolicExpression loc : arg) {
				loc = removeTypingExpressions(loc);
				if (loc instanceof AllocationSite) {
					AllocationSite allocSite = (AllocationSite) loc;
					MemoryPointer e = new MemoryPointer(
							new ReferenceType(loc.getStaticType()),
							allocSite,
							loc.getCodeLocation());

					// propagates the annotations of the allocation site
					// to the newly created memory pointer
					for (Annotation ann : allocSite.getAnnotations())
						e.addAnnotation(ann);

					result.add(e);
				} else
					result.add(loc);
			}
			return new ExpressionSet(result);
		}

		@Override
		public ExpressionSet visit(
				HeapDereference expression,
				ExpressionSet arg,
				Object... params)
				throws SemanticException {
			Set result = new HashSet<>();

			for (SymbolicExpression ref : arg) {
				ref = removeTypingExpressions(ref);
				if (ref instanceof MemoryPointer)
					result.add(((MemoryPointer) ref).getReferencedLocation());
				else if (ref instanceof Identifier) {
					// this could be aliasing!
					Identifier id = (Identifier) ref;
					if (heapEnv.getKeys().contains(id))
						result.addAll(resolveIdentifier(id));
					else if (id instanceof Variable) {
						// this is a variable from the program that we know
						// nothing about
						CodeLocation loc = expression.getCodeLocation();
						AllocationSite site;
						if (id.getStaticType().isPointerType())
							site = new HeapAllocationSite(id.getStaticType(), "unknown@" + id.getName(), true, loc);
						else if (id.getStaticType().isInMemoryType() || id.getStaticType().isUntyped())
							site = new StackAllocationSite(id.getStaticType(), "unknown@" + id.getName(), true, loc);
						else
							throw new SemanticException("The type " + id.getStaticType()
									+ " cannot be allocated by point-based heap domains");

						// propagates the annotations of the variable
						// to the newly created allocation site
						for (Annotation ann : id.getAnnotations())
							site.addAnnotation(ann);

						result.add(site);
					}
				} else
					result.add(ref);
			}

			return new ExpressionSet(result);
		}

		@Override
		public ExpressionSet visit(
				Identifier expression,
				Object... params)
				throws SemanticException {
			if (!(expression instanceof MemoryPointer) && heapEnv.getKeys().contains(expression))
				return new ExpressionSet(resolveIdentifier(expression));

			return new ExpressionSet(expression);
		}

		private Set resolveIdentifier(
				Identifier v) {
			Set result = new HashSet<>();
			for (AllocationSite site : heapEnv.getState(v)) {
				MemoryPointer e = new MemoryPointer(
						new ReferenceType(site.getStaticType()),
						site,
						site.getCodeLocation());
				result.add(e);
			}

			return result;
		}

		@Override
		public ExpressionSet visit(
				PushAny expression,
				Object... params)
				throws SemanticException {
			if (expression.getStaticType().isPointerType()) {
				Type inner = expression.getStaticType().asPointerType().getInnerType();
				CodeLocation loc = expression.getCodeLocation();
				HeapAllocationSite site = new HeapAllocationSite(inner, "unknown@" + loc.getCodeLocation(), false, loc);
				return new ExpressionSet(new MemoryPointer(expression.getStaticType(), site, loc));
			} else if (expression.getStaticType().isInMemoryType()) {
				Type type = expression.getStaticType();
				CodeLocation loc = expression.getCodeLocation();
				StackAllocationSite site = new StackAllocationSite(type, "unknown@" + loc.getCodeLocation(), false,
						loc);
				return new ExpressionSet(new MemoryPointer(expression.getStaticType(), site, loc));
			}
			return new ExpressionSet(expression);
		}
	}

	@Override
	public boolean knowsIdentifier(
			Identifier id) {
		return heapEnv.knowsIdentifier(id) || (id instanceof AllocationSite
				&& heapEnv.getValues().stream().anyMatch(as -> as.contains((AllocationSite) id)));
	}

	@Override
	public Satisfiability alias(
			SymbolicExpression x,
			SymbolicExpression y,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		if (isTop())
			return Satisfiability.UNKNOWN;
		if (isBottom())
			return Satisfiability.BOTTOM;

		boolean atLeastOne = false;
		boolean all = true;

		ExpressionSet xrs = rewrite(x, pp, oracle);
		ExpressionSet yrs = rewrite(y, pp, oracle);

		for (SymbolicExpression xr : xrs)
			for (SymbolicExpression yr : yrs)
				if (xr instanceof MemoryPointer && yr instanceof MemoryPointer) {
					HeapLocation xloc = ((MemoryPointer) xr).getReferencedLocation();
					HeapLocation yloc = ((MemoryPointer) yr).getReferencedLocation();
					if (xloc.equals(yloc)) {
						atLeastOne = true;
						all &= true;
					} else
						all = false;
				} else
					// they cannot be alias
					all = false;

		if (all && atLeastOne)
			return Satisfiability.SATISFIED;
		else if (atLeastOne)
			return Satisfiability.UNKNOWN;
		else
			return Satisfiability.NOT_SATISFIED;
	}

	@Override
	public Satisfiability isReachableFrom(
			SymbolicExpression x,
			SymbolicExpression y,
			ProgramPoint pp,
			SemanticOracle oracle)
			throws SemanticException {
		if (isTop())
			return Satisfiability.UNKNOWN;
		if (isBottom())
			return Satisfiability.BOTTOM;

		WorkingSet ws = VisitOnceFIFOWorkingSet.mk();
		rewrite(x, pp, oracle).elements().forEach(ws::push);
		ExpressionSet targets = rewrite(y, pp, oracle);

		while (!ws.isEmpty()) {
			SymbolicExpression current = ws.peek();
			if (targets.elements().contains(current))
				return Satisfiability.SATISFIED;

			if (current instanceof Identifier && heapEnv.knowsIdentifier((Identifier) current))
				heapEnv.getState((Identifier) current).elements().forEach(ws::push);
			else
				rewrite(current, pp, oracle).elements().forEach(ws::push);
		}

		return Satisfiability.NOT_SATISFIED;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy