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

it.unive.lisa.analysis.SimpleAbstractState Maven / Gradle / Ivy

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

import it.unive.lisa.analysis.heap.HeapDomain;
import it.unive.lisa.analysis.heap.HeapSemanticOperation.HeapReplacement;
import it.unive.lisa.analysis.lattices.ExpressionSet;
import it.unive.lisa.analysis.lattices.Satisfiability;
import it.unive.lisa.analysis.type.TypeDomain;
import it.unive.lisa.analysis.value.ValueDomain;
import it.unive.lisa.program.cfg.ProgramPoint;
import it.unive.lisa.symbolic.SymbolicExpression;
import it.unive.lisa.symbolic.heap.MemoryAllocation;
import it.unive.lisa.symbolic.value.Identifier;
import it.unive.lisa.symbolic.value.ValueExpression;
import it.unive.lisa.type.Type;
import it.unive.lisa.util.representation.ObjectRepresentation;
import it.unive.lisa.util.representation.StructuredRepresentation;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

/**
 * An abstract state of the analysis, composed by a heap state modeling the
 * memory layout, a value state modeling values of program variables and memory
 * locations, and a type state that can give types to expressions knowing the
 * ones of variables.
*
* The interaction between heap and value/type domains follows the one defined * in this * paper. * * @author Luca Negrini * * @param the type of {@link HeapDomain} embedded in this state * @param the type of {@link ValueDomain} embedded in this state * @param the type of {@link TypeDomain} embedded in this state */ public class SimpleAbstractState, V extends ValueDomain, T extends TypeDomain> implements BaseLattice>, AbstractState> { /** * The key that should be used to store the instance of {@link HeapDomain} * inside the {@link StructuredRepresentation} returned by * {@link #representation()}. */ public static final String HEAP_REPRESENTATION_KEY = "heap"; /** * The key that should be used to store the instance of {@link TypeDomain} * inside the {@link StructuredRepresentation} returned by * {@link #representation()}. */ public static final String TYPE_REPRESENTATION_KEY = "type"; /** * The key that should be used to store the instance of {@link ValueDomain} * inside the {@link StructuredRepresentation} returned by * {@link #representation()}. */ public static final String VALUE_REPRESENTATION_KEY = "value"; /** * The domain containing information regarding heap structures */ private final H heapState; /** * The domain containing information regarding values of program variables * and concretized memory locations */ private final V valueState; /** * The domain containing runtime types information regarding runtime types * of program variables and concretized memory locations */ private final T typeState; /** * Builds a new abstract state. * * @param heapState the domain containing information regarding heap * structures * @param valueState the domain containing information regarding values of * program variables and concretized memory locations * @param typeState the domain containing information regarding runtime * types of program variables and concretized memory * locations */ public SimpleAbstractState( H heapState, V valueState, T typeState) { this.heapState = heapState; this.valueState = valueState; this.typeState = typeState; } /** * Yields the {@link HeapDomain} contained in this state. * * @return the heap domain */ public H getHeapState() { return heapState; } /** * Yields the {@link ValueDomain} contained in this state. * * @return the value domain */ public V getValueState() { return valueState; } /** * Yields the {@link TypeDomain} contained in this state. * * @return the type domain */ public T getTypeState() { return typeState; } @Override public SimpleAbstractState assign( Identifier id, SymbolicExpression expression, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { if (!expression.mightNeedRewriting()) { ValueExpression ve = (ValueExpression) expression; return new SimpleAbstractState<>( heapState.assign(id, expression, pp, this), valueState.assign(id, ve, pp, this), typeState.assign(id, ve, pp, this)); } MutableOracle mo = new MutableOracle<>(heapState, valueState, typeState); mo.heap = mo.heap.assign(id, expression, pp, mo); ExpressionSet exprs = mo.heap.rewrite(expression, pp, mo); if (exprs.isEmpty()) return bottom(); applySubstitution(mo, pp); if (exprs.elements.size() == 1) { SymbolicExpression expr = exprs.elements.iterator().next(); if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.assign(id, ve, pp, mo); V v = mo.value.assign(id, ve, pp, mo); return new SimpleAbstractState<>(mo.heap, v, t); } T typeRes = mo.type.bottom(); V valueRes = mo.value.bottom(); for (SymbolicExpression expr : exprs) { if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.assign(id, ve, pp, mo); V v = mo.value.assign(id, ve, pp, mo); typeRes = typeRes.lub(t); valueRes = valueRes.lub(v); } return new SimpleAbstractState<>(mo.heap, valueRes, typeRes); } @Override public SimpleAbstractState smallStepSemantics( SymbolicExpression expression, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { if (!expression.mightNeedRewriting()) { ValueExpression ve = (ValueExpression) expression; return new SimpleAbstractState<>( heapState.smallStepSemantics(expression, pp, this), valueState.smallStepSemantics(ve, pp, this), typeState.smallStepSemantics(ve, pp, this)); } MutableOracle mo = new MutableOracle<>(heapState, valueState, typeState); mo.heap = mo.heap.smallStepSemantics(expression, pp, mo); ExpressionSet exprs = mo.heap.rewrite(expression, pp, mo); if (exprs.isEmpty()) return bottom(); applySubstitution(mo, pp); if (exprs.elements.size() == 1) { SymbolicExpression expr = exprs.elements.iterator().next(); if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.smallStepSemantics(ve, pp, mo); if (expression instanceof MemoryAllocation && expr instanceof Identifier) // if the expression is a memory allocation, its type is // registered in the type domain t = t.assign((Identifier) ve, ve, pp, mo); V v = mo.value.smallStepSemantics(ve, pp, mo); return new SimpleAbstractState<>(mo.heap, v, t); } T typeRes = mo.type.bottom(); V valueRes = mo.value.bottom(); for (SymbolicExpression expr : exprs) { if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.smallStepSemantics(ve, pp, mo); if (expression instanceof MemoryAllocation && expr instanceof Identifier) // if the expression is a memory allocation, its type is // registered in the type domain t = t.assign((Identifier) ve, ve, pp, mo); V v = mo.value.smallStepSemantics(ve, pp, mo); typeRes = typeRes.lub(t); valueRes = valueRes.lub(v); } return new SimpleAbstractState<>(mo.heap, valueRes, typeRes); } private static , V extends ValueDomain, T extends TypeDomain> void applySubstitution( MutableOracle mo, ProgramPoint pp) throws SemanticException { List subs = mo.heap.getSubstitution(); if (subs != null) for (HeapReplacement repl : subs) { T t = mo.type.applyReplacement(repl, pp, mo); V v = mo.value.applyReplacement(repl, pp, mo); // we update the oracle after both replacements have been // applied to not lose info on the sources that will be removed mo.type = t; mo.value = v; } } @Override public SimpleAbstractState assume( SymbolicExpression expression, ProgramPoint src, ProgramPoint dest, SemanticOracle oracle) throws SemanticException { if (!expression.mightNeedRewriting()) { ValueExpression ve = (ValueExpression) expression; H h = heapState.assume(expression, src, dest, this); if (h.isBottom()) return bottom(); T t = typeState.assume(ve, src, dest, this); if (t.isBottom()) return bottom(); V v = valueState.assume(ve, src, dest, this); if (v.isBottom()) return bottom(); return new SimpleAbstractState<>(h, v, t); } MutableOracle mo = new MutableOracle<>(heapState, valueState, typeState); mo.heap = mo.heap.assume(expression, src, dest, mo); if (mo.heap.isBottom()) return bottom(); ExpressionSet exprs = mo.heap.rewrite(expression, src, mo); if (exprs.isEmpty()) return bottom(); applySubstitution(mo, src); if (exprs.elements.size() == 1) { SymbolicExpression expr = exprs.elements.iterator().next(); if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.assume(ve, src, dest, mo); if (t.isBottom()) return bottom(); V v = mo.value.assume(ve, src, dest, mo); if (v.isBottom()) return bottom(); return new SimpleAbstractState<>(mo.heap, v, t); } T typeRes = mo.type.bottom(); V valueRes = mo.value.bottom(); for (SymbolicExpression expr : exprs) { if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; T t = mo.type.assume(ve, src, dest, mo); V v = mo.value.assume(ve, src, dest, mo); typeRes = typeRes.lub(t); valueRes = valueRes.lub(v); } if (typeRes.isBottom() || valueRes.isBottom()) return bottom(); return new SimpleAbstractState<>(mo.heap, valueRes, typeRes); } @Override public Satisfiability satisfies( SymbolicExpression expression, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { Satisfiability heapsat = heapState.satisfies(expression, pp, this); if (heapsat == Satisfiability.BOTTOM) return Satisfiability.BOTTOM; if (!expression.mightNeedRewriting()) { ValueExpression ve = (ValueExpression) expression; Satisfiability typesat = typeState.satisfies(ve, pp, this); if (typesat == Satisfiability.BOTTOM) return Satisfiability.BOTTOM; Satisfiability valuesat = valueState.satisfies(ve, pp, this); if (valuesat == Satisfiability.BOTTOM) return Satisfiability.BOTTOM; return heapsat.glb(typesat).glb(valuesat); } ExpressionSet exprs = heapState.rewrite(expression, pp, this); if (exprs.isEmpty()) return Satisfiability.BOTTOM; if (exprs.elements.size() == 1) { SymbolicExpression expr = exprs.elements.iterator().next(); if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expression; Satisfiability typesat = typeState.satisfies(ve, pp, this); if (typesat == Satisfiability.BOTTOM) return Satisfiability.BOTTOM; Satisfiability valuesat = valueState.satisfies(ve, pp, this); if (valuesat == Satisfiability.BOTTOM) return Satisfiability.BOTTOM; return heapsat.glb(typesat).glb(valuesat); } Satisfiability typesat = Satisfiability.BOTTOM; Satisfiability valuesat = Satisfiability.BOTTOM; for (SymbolicExpression expr : exprs) { if (!(expr instanceof ValueExpression)) throw new SemanticException("Rewriting failed for expression " + expr); ValueExpression ve = (ValueExpression) expr; Satisfiability sat = typeState.satisfies(ve, pp, this); if (sat == Satisfiability.BOTTOM) return sat; typesat = typesat.lub(sat); sat = valueState.satisfies(ve, pp, this); if (sat == Satisfiability.BOTTOM) return sat; valuesat = valuesat.lub(sat); } return heapsat.glb(typesat).glb(valuesat); } @Override public SimpleAbstractState pushScope( ScopeToken scope) throws SemanticException { return new SimpleAbstractState<>( heapState.pushScope(scope), valueState.pushScope(scope), typeState.pushScope(scope)); } @Override public SimpleAbstractState popScope( ScopeToken scope) throws SemanticException { return new SimpleAbstractState<>( heapState.popScope(scope), valueState.popScope(scope), typeState.popScope(scope)); } @Override public SimpleAbstractState lubAux( SimpleAbstractState other) throws SemanticException { return new SimpleAbstractState<>( heapState.lub(other.heapState), valueState.lub(other.valueState), typeState.lub(other.typeState)); } @Override public SimpleAbstractState glbAux( SimpleAbstractState other) throws SemanticException { return new SimpleAbstractState<>( heapState.glb(other.heapState), valueState.glb(other.valueState), typeState.glb(other.typeState)); } @Override public SimpleAbstractState wideningAux( SimpleAbstractState other) throws SemanticException { return new SimpleAbstractState<>( heapState.widening(other.heapState), valueState.widening(other.valueState), typeState.widening(other.typeState)); } @Override public SimpleAbstractState narrowingAux( SimpleAbstractState other) throws SemanticException { return new SimpleAbstractState<>( heapState.narrowing(other.heapState), valueState.narrowing(other.valueState), typeState.narrowing(other.typeState)); } @Override public boolean lessOrEqualAux( SimpleAbstractState other) throws SemanticException { return heapState.lessOrEqual(other.heapState) && valueState.lessOrEqual(other.valueState) && typeState.lessOrEqual(other.typeState); } @Override public SimpleAbstractState top() { return new SimpleAbstractState<>(heapState.top(), valueState.top(), typeState.top()); } @Override public SimpleAbstractState bottom() { return new SimpleAbstractState<>(heapState.bottom(), valueState.bottom(), typeState.bottom()); } @Override public boolean isTop() { return heapState.isTop() && valueState.isTop() && typeState.isTop(); } @Override public boolean isBottom() { return heapState.isBottom() && valueState.isBottom() && typeState.isBottom(); } @Override public SimpleAbstractState forgetIdentifier( Identifier id) throws SemanticException { return new SimpleAbstractState<>( heapState.forgetIdentifier(id), valueState.forgetIdentifier(id), typeState.forgetIdentifier(id)); } @Override public SimpleAbstractState forgetIdentifiersIf( Predicate test) throws SemanticException { return new SimpleAbstractState<>( heapState.forgetIdentifiersIf(test), valueState.forgetIdentifiersIf(test), typeState.forgetIdentifiersIf(test)); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((heapState == null) ? 0 : heapState.hashCode()); result = prime * result + ((valueState == null) ? 0 : valueState.hashCode()); result = prime * result + ((typeState == null) ? 0 : typeState.hashCode()); return result; } @Override public boolean equals( Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SimpleAbstractState other = (SimpleAbstractState) obj; if (heapState == null) { if (other.heapState != null) return false; } else if (!heapState.equals(other.heapState)) return false; if (valueState == null) { if (other.valueState != null) return false; } else if (!valueState.equals(other.valueState)) return false; if (typeState == null) { if (other.typeState != null) return false; } else if (!typeState.equals(other.typeState)) return false; return true; } @Override public StructuredRepresentation representation() { if (isBottom()) return Lattice.bottomRepresentation(); if (isTop()) return Lattice.topRepresentation(); StructuredRepresentation h = heapState.representation(); StructuredRepresentation t = typeState.representation(); StructuredRepresentation v = valueState.representation(); return new ObjectRepresentation(Map.of( HEAP_REPRESENTATION_KEY, h, TYPE_REPRESENTATION_KEY, t, VALUE_REPRESENTATION_KEY, v)); } @Override public String toString() { return representation().toString(); } @Override public > Collection getAllDomainInstances( Class domain) { Collection result = AbstractState.super.getAllDomainInstances(domain); result.addAll(heapState.getAllDomainInstances(domain)); result.addAll(typeState.getAllDomainInstances(domain)); result.addAll(valueState.getAllDomainInstances(domain)); return result; } @Override public ExpressionSet rewrite( SymbolicExpression expression, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { if (!expression.mightNeedRewriting()) return new ExpressionSet(expression); return heapState.rewrite(expression, pp, oracle); } @Override public ExpressionSet rewrite( ExpressionSet expressions, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return heapState.rewrite(expressions, pp, oracle); } @Override public Set getRuntimeTypesOf( SymbolicExpression e, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return typeState.getRuntimeTypesOf(e, pp, oracle); } @Override public Type getDynamicTypeOf( SymbolicExpression e, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return typeState.getDynamicTypeOf(e, pp, oracle); } @Override public boolean knowsIdentifier( Identifier id) { return heapState.knowsIdentifier(id) || valueState.knowsIdentifier(id) || typeState.knowsIdentifier(id); } @Override public SimpleAbstractState withTopMemory() { return new SimpleAbstractState<>(heapState.top(), valueState, typeState); } @Override public SimpleAbstractState withTopValues() { return new SimpleAbstractState<>(heapState, valueState.top(), typeState); } @Override public SimpleAbstractState withTopTypes() { return new SimpleAbstractState<>(heapState, valueState, typeState.top()); } private static class MutableOracle, V extends ValueDomain, T extends TypeDomain> implements SemanticOracle { private H heap; private V value; private T type; public MutableOracle( H heap, V value, T type) { this.heap = heap; this.value = value; this.type = type; } @Override public ExpressionSet rewrite( SymbolicExpression expression, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { if (!expression.mightNeedRewriting()) return new ExpressionSet(expression); return heap.rewrite(expression, pp, this); } @Override public Set getRuntimeTypesOf( SymbolicExpression e, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return type.getRuntimeTypesOf(e, pp, this); } @Override public Type getDynamicTypeOf( SymbolicExpression e, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return type.getDynamicTypeOf(e, pp, this); } @Override public String toString() { if (heap.isBottom() || type.isBottom() || value.isBottom()) return Lattice.bottomRepresentation().toString(); if (heap.isTop() && type.isTop() && value.isTop()) return Lattice.topRepresentation().toString(); StructuredRepresentation h = heap.representation(); StructuredRepresentation t = type.representation(); StructuredRepresentation v = value.representation(); return new ObjectRepresentation(Map.of( HEAP_REPRESENTATION_KEY, h, TYPE_REPRESENTATION_KEY, t, VALUE_REPRESENTATION_KEY, v)).toString(); } @Override public Satisfiability alias( SymbolicExpression x, SymbolicExpression y, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return heap.alias(x, y, pp, oracle); } @Override public Satisfiability isReachableFrom( SymbolicExpression x, SymbolicExpression y, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return heap.isReachableFrom(x, y, pp, oracle); } } @Override public Satisfiability alias( SymbolicExpression x, SymbolicExpression y, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return heapState.alias(x, y, pp, oracle); } @Override public Satisfiability isReachableFrom( SymbolicExpression x, SymbolicExpression y, ProgramPoint pp, SemanticOracle oracle) throws SemanticException { return heapState.isReachableFrom(x, y, pp, oracle); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy