/* * CompositeState.java - This file is part of the Jakstab project. * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org> * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, see <http://www.gnu.org/licenses/>. */ package org.jakstab.analysis.composite; import java.util.Arrays; import java.util.Set; import org.jakstab.analysis.*; import org.jakstab.analysis.location.LocationState; import org.jakstab.cfa.Location; import org.jakstab.rtl.expressions.RTLExpression; import org.jakstab.rtl.expressions.RTLNumber; import org.jakstab.util.FastSet; import org.jakstab.util.Logger; import org.jakstab.util.Tuple; /** * A cartesian product state that consists of a vector of substates where the * first substate is guaranteed to be a location state. * * @author Johannes Kinder */ public class CompositeState implements AbstractState { @SuppressWarnings("unused") private static final Logger logger = Logger.getLogger(CompositeState.class); protected final AbstractState[] components; /** * @param components */ public CompositeState(AbstractState[] components) { super(); this.components = components; } @Override public String getIdentifier() { StringBuilder id = new StringBuilder(); id.append("ID"); for (AbstractState c : components) id.append(c.getIdentifier()).append(":"); return id.toString(); } @Override public Location getLocation() { return ((LocationState)components[0]).getLocation(); } public AbstractState getComponent(int index) { return components[index]; } public int numComponents() { return components.length; } @Override public AbstractState join(LatticeElement l) { CompositeState other = (CompositeState)l; AbstractState[] jComponents = new AbstractState[components.length]; for (int i=0; i<components.length; i++) { jComponents[i] = components[i].join(other.components[i]); } return new CompositeState(jComponents); } @Override public Set<Tuple<RTLNumber>> projectionFromConcretization( RTLExpression... expressions) { Set<Tuple<RTLNumber>> result = null; for (int i=0; i<components.length; i++) { // Concretize this component state and then intersect it with existing ones Set<Tuple<RTLNumber>> concreteTuples = components[i].projectionFromConcretization(expressions); //logger.info(concreteTuples); /* Return value of null represents the whole set of tuples of numbers (usually b/c the function * is not implemented), so intersection has no effect */ if (concreteTuples == null) continue; /* If we are currently at the whole set, the new tuple set is the intersection */ else if (result == null) result = concreteTuples; /* Else intersect */ else { // result.retainAll(concreteTuples); // intersect manually b/c of possible null components (wildcards for more tuples) // Note: A tuple with a null component expands to a set of tuples // with all possible values for that component // Set<Tuple<RTLNumber>> newResult = new FastSet<Tuple<RTLNumber>>(); // for all tuples in result for (Tuple<RTLNumber> rTuple : result) { // for all tuples we got from the current substate cTuplesLoop: for (Tuple<RTLNumber> cTuple : concreteTuples) { // array for building new tuple RTLNumber[] numbers = new RTLNumber[expressions.length]; // match components of both tuples against each other for (int j=0; j<expressions.length; j++) { RTLNumber cNumber = cTuple.get(j); RTLNumber rNumber = rTuple.get(j); // if the component is no wildcard and not equal, don't match, try next new tuple for match if (cNumber != RTLNumber.WILDCARD && rNumber != null && !cNumber.equals(rNumber)) { continue cTuplesLoop; } else { // handle wildcards on both sides: if (rNumber == RTLNumber.WILDCARD) numbers[j] = cNumber; else numbers[j] = rNumber; } } // We passed all components - so add matching tuple newResult.add(Tuple.create(numbers)); // We still need to continue with the next tuple, since wildcards // could allow more possibilities } // cTuplesLoop finished without finding a match } result = newResult; } } //logger.info("Project " + Arrays.toString(expressions) + " to " + result); assert result != null; return result; } @Override public boolean isBot() { return false; } @Override public boolean isTop() { return false; } @Override public boolean lessOrEqual(LatticeElement l) { CompositeState other = (CompositeState)l; for (int i=0; i<components.length; i++) { if (!(components[i].lessOrEqual(other.components[i]))) return false; } return true; } @Override public String toString() { StringBuilder res = new StringBuilder(); res.append('('); for (int i=0; i<components.length - 1; i++) { res.append(components[i].toString()); res.append(','); } res.append(components[components.length - 1].toString()); res.append(')'); return res.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(components); return result; } @Override public boolean equals(Object obj) { if (obj == null) return false; CompositeState other = (CompositeState) obj; if (!Arrays.equals(components, other.components)) return false; return true; } }