it.unive.lisa.analysis.numeric.Sign Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lisa-analyses Show documentation
Show all versions of lisa-analyses Show documentation
A library for static analysis
The newest version!
package it.unive.lisa.analysis.numeric;
import it.unive.lisa.analysis.BaseLattice;
import it.unive.lisa.analysis.Lattice;
import it.unive.lisa.analysis.SemanticException;
import it.unive.lisa.analysis.SemanticOracle;
import it.unive.lisa.analysis.lattices.Satisfiability;
import it.unive.lisa.analysis.nonrelational.value.BaseNonRelationalValueDomain;
import it.unive.lisa.analysis.nonrelational.value.ValueEnvironment;
import it.unive.lisa.program.cfg.ProgramPoint;
import it.unive.lisa.symbolic.value.Constant;
import it.unive.lisa.symbolic.value.Identifier;
import it.unive.lisa.symbolic.value.ValueExpression;
import it.unive.lisa.symbolic.value.operator.AdditionOperator;
import it.unive.lisa.symbolic.value.operator.DivisionOperator;
import it.unive.lisa.symbolic.value.operator.ModuloOperator;
import it.unive.lisa.symbolic.value.operator.MultiplicationOperator;
import it.unive.lisa.symbolic.value.operator.RemainderOperator;
import it.unive.lisa.symbolic.value.operator.SubtractionOperator;
import it.unive.lisa.symbolic.value.operator.binary.BinaryOperator;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonEq;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonGe;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonGt;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonLe;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonLt;
import it.unive.lisa.symbolic.value.operator.binary.ComparisonNe;
import it.unive.lisa.symbolic.value.operator.ternary.TernaryOperator;
import it.unive.lisa.symbolic.value.operator.unary.NumericNegation;
import it.unive.lisa.symbolic.value.operator.unary.UnaryOperator;
import it.unive.lisa.util.representation.StringRepresentation;
import it.unive.lisa.util.representation.StructuredRepresentation;
/**
* The basic overflow-insensitive Sign abstract domain, tracking zero, strictly
* positive and strictly negative integer values, implemented as a
* {@link BaseNonRelationalValueDomain}, handling top and bottom values for the
* expression evaluation and bottom values for the expression satisfiability.
* Top and bottom cases for least upper bounds, widening and less or equals
* operations are handled by {@link BaseLattice} in {@link BaseLattice#lub},
* {@link BaseLattice#widening} and {@link BaseLattice#lessOrEqual} methods,
* respectively.
*
* @author Vincenzo Arceri
*/
public class Sign implements BaseNonRelationalValueDomain {
/**
* The abstract positive element.
*/
public static final Sign POS = new Sign((byte) 4);
/**
* The abstract negative element.
*/
public static final Sign NEG = new Sign((byte) 3);
/**
* The abstract zero element.
*/
public static final Sign ZERO = new Sign((byte) 2);
/**
* The abstract top element.
*/
public static final Sign TOP = new Sign((byte) 0);
/**
* The abstract bottom element.
*/
public static final Sign BOTTOM = new Sign((byte) 1);
private final byte sign;
/**
* Builds the sign abstract domain, representing the top of the sign
* abstract domain.
*/
public Sign() {
this((byte) 0);
}
/**
* Builds the sign instance for the given sign value.
*
* @param sign the sign (0 = top, 1 = bottom, 2 = zero, 3 = negative, 4 =
* positive)
*/
public Sign(
byte sign) {
this.sign = sign;
}
@Override
public Sign top() {
return TOP;
}
@Override
public Sign bottom() {
return BOTTOM;
}
@Override
public String toString() {
return representation().toString();
}
@Override
public StructuredRepresentation representation() {
if (isBottom())
return Lattice.bottomRepresentation();
if (isTop())
return Lattice.topRepresentation();
String repr;
if (this == ZERO)
repr = "0";
else if (this == POS)
repr = "+";
else
repr = "-";
return new StringRepresentation(repr);
}
@Override
public Sign evalNullConstant(
ProgramPoint pp,
SemanticOracle oracle) {
return top();
}
@Override
public Sign evalNonNullConstant(
Constant constant,
ProgramPoint pp,
SemanticOracle oracle) {
if (constant.getValue() instanceof Integer) {
Integer i = (Integer) constant.getValue();
return i == 0 ? ZERO : i > 0 ? POS : NEG;
}
return top();
}
/**
* Yields whether or not this is the positive sign.
*
* @return {@code true} if that condition holds
*/
public boolean isPositive() {
return this == POS;
}
/**
* Yields whether or not this is the zero sign.
*
* @return {@code true} if that condition holds
*/
public boolean isZero() {
return this == ZERO;
}
/**
* Yields whether or not this is the negative sign.
*
* @return {@code true} if that condition holds
*/
public boolean isNegative() {
return this == NEG;
}
/**
* Yields the sign opposite to this one. Top and bottom elements do not
* change.
*
* @return the opposite sign
*/
public Sign opposite() {
if (isTop() || isBottom())
return this;
return isPositive() ? NEG : isNegative() ? POS : ZERO;
}
@Override
public Sign evalUnaryExpression(
UnaryOperator operator,
Sign arg,
ProgramPoint pp,
SemanticOracle oracle) {
if (operator == NumericNegation.INSTANCE)
if (arg.isPositive())
return NEG;
else if (arg.isNegative())
return POS;
else if (arg.isZero())
return ZERO;
else
return TOP;
return TOP;
}
@Override
public Sign evalBinaryExpression(
BinaryOperator operator,
Sign left,
Sign right,
ProgramPoint pp,
SemanticOracle oracle) {
if (operator instanceof AdditionOperator)
if (left.isZero())
return right;
else if (right.isZero())
return left;
else if (left.equals(right))
return left;
else
return top();
else if (operator instanceof SubtractionOperator)
if (left.isZero())
return right.opposite();
else if (right.isZero())
return left;
else if (left.equals(right))
return top();
else
return left;
else if (operator instanceof DivisionOperator)
if (right.isZero())
return bottom();
else if (left.isZero())
return ZERO;
else if (left.equals(right))
// top/top = top
// +/+ = +
// -/- = +
return left.isTop() ? left : POS;
else if (!left.isTop() && left.equals(right.opposite()))
// +/- = -
// -/+ = -
return NEG;
else
return top();
else if (operator instanceof ModuloOperator)
return right;
else if (operator instanceof RemainderOperator)
return left;
else if (operator instanceof MultiplicationOperator)
if (left.isZero() || right.isZero())
return ZERO;
else if (left.equals(right))
return POS;
else
return NEG;
else
return TOP;
}
@Override
public Sign lubAux(
Sign other)
throws SemanticException {
return TOP;
}
@Override
public boolean lessOrEqualAux(
Sign other)
throws SemanticException {
return false;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + sign;
return result;
}
@Override
public boolean equals(
Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Sign other = (Sign) obj;
if (sign != other.sign)
return false;
return true;
}
@Override
public Satisfiability satisfiesBinaryExpression(
BinaryOperator operator,
Sign left,
Sign right,
ProgramPoint pp,
SemanticOracle oracle) {
if (left.isTop() || right.isTop())
return Satisfiability.UNKNOWN;
if (operator == ComparisonEq.INSTANCE)
return left.eq(right);
else if (operator == ComparisonGe.INSTANCE)
return left.eq(right).or(left.gt(right));
else if (operator == ComparisonGt.INSTANCE)
return left.gt(right);
else if (operator == ComparisonLe.INSTANCE)
// e1 <= e2 same as !(e1 > e2)
return left.gt(right).negate();
else if (operator == ComparisonLt.INSTANCE)
// e1 < e2 -> !(e1 >= e2) && !(e1 == e2)
return left.gt(right).negate().and(left.eq(right).negate());
else if (operator == ComparisonNe.INSTANCE)
return left.eq(right).negate();
else
return Satisfiability.UNKNOWN;
}
/**
* Tests if this instance is equal to the given one, returning a
* {@link Satisfiability} element.
*
* @param other the instance
*
* @return the satisfiability of {@code this = other}
*/
public Satisfiability eq(
Sign other) {
if (!this.equals(other))
return Satisfiability.NOT_SATISFIED;
else if (isZero())
return Satisfiability.SATISFIED;
else
return Satisfiability.UNKNOWN;
}
/**
* Tests if this instance is greater than the given one, returning a
* {@link Satisfiability} element.
*
* @param other the instance
*
* @return the satisfiability of {@code this > other}
*/
public Satisfiability gt(
Sign other) {
if (this.equals(other))
return this.isZero() ? Satisfiability.NOT_SATISFIED : Satisfiability.UNKNOWN;
else if (this.isZero())
return other.isPositive() ? Satisfiability.NOT_SATISFIED : Satisfiability.SATISFIED;
else if (this.isPositive())
return Satisfiability.SATISFIED;
else
return Satisfiability.NOT_SATISFIED;
}
@Override
public Satisfiability satisfiesTernaryExpression(
TernaryOperator operator,
Sign left,
Sign middle,
Sign right,
ProgramPoint pp,
SemanticOracle oracle) {
return Satisfiability.UNKNOWN;
}
@Override
public ValueEnvironment assumeBinaryExpression(
ValueEnvironment environment,
BinaryOperator operator,
ValueExpression left,
ValueExpression right,
ProgramPoint src,
ProgramPoint dest,
SemanticOracle oracle)
throws SemanticException {
Identifier id;
Sign eval;
boolean rightIsExpr;
if (left instanceof Identifier) {
eval = eval(right, environment, src, oracle);
id = (Identifier) left;
rightIsExpr = true;
} else if (right instanceof Identifier) {
eval = eval(left, environment, src, oracle);
id = (Identifier) right;
rightIsExpr = false;
} else
return environment;
Sign starting = environment.getState(id);
if (eval.isBottom() || starting.isBottom())
return environment.bottom();
Sign update = null;
if (operator == ComparisonEq.INSTANCE)
update = eval;
else if (operator == ComparisonGe.INSTANCE) {
if (rightIsExpr && eval.isPositive())
update = eval;
else if (!rightIsExpr && eval.isNegative())
update = eval;
} else if (operator == ComparisonLe.INSTANCE) {
if (rightIsExpr && eval.isNegative())
update = eval;
else if (!rightIsExpr && eval.isPositive())
update = eval;
} else if (operator == ComparisonLt.INSTANCE) {
if (rightIsExpr && (eval.isNegative() || eval.isZero()))
// x < 0/-
update = NEG;
else if (!rightIsExpr && (eval.isPositive() || eval.isZero()))
// 0/+ < x
update = POS;
} else if (operator == ComparisonGt.INSTANCE) {
if (rightIsExpr && (eval.isPositive() || eval.isZero()))
// x > +/0
update = POS;
else if (!rightIsExpr && (eval.isNegative() || eval.isZero()))
// -/0 > x
update = NEG;
}
if (update == null)
return environment;
else if (update.isBottom())
return environment.bottom();
else
return environment.putState(id, update);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy