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

org.evosuite.symbolic.solver.z3.Z3Solver Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite 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
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.symbolic.solver.z3;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.evosuite.Properties;
import org.evosuite.symbolic.expr.Constraint;
import org.evosuite.symbolic.expr.Variable;
import org.evosuite.symbolic.solver.SmtExprBuilder;
import org.evosuite.symbolic.solver.SmtSolver;
import org.evosuite.symbolic.solver.SolverEmptyQueryException;
import org.evosuite.symbolic.solver.SolverErrorException;
import org.evosuite.symbolic.solver.SolverParseException;
import org.evosuite.symbolic.solver.SolverResult;
import org.evosuite.symbolic.solver.SolverTimeoutException;
import org.evosuite.symbolic.solver.smt.SmtAssertion;
import org.evosuite.symbolic.solver.smt.SmtConstantDeclaration;
import org.evosuite.symbolic.solver.smt.SmtExpr;
import org.evosuite.symbolic.solver.smt.SmtFunctionDefinition;
import org.evosuite.symbolic.solver.smt.SmtIntVariable;
import org.evosuite.symbolic.solver.smt.SmtModelParser;
import org.evosuite.symbolic.solver.smt.SmtOperation;
import org.evosuite.symbolic.solver.smt.SmtOperation.Operator;
import org.evosuite.symbolic.solver.smt.SmtOperatorCollector;
import org.evosuite.symbolic.solver.smt.SmtQuery;
import org.evosuite.symbolic.solver.smt.SmtQueryPrinter;
import org.evosuite.symbolic.solver.smt.SmtRealVariable;
import org.evosuite.symbolic.solver.smt.SmtStringVariable;
import org.evosuite.symbolic.solver.smt.SmtVariable;
import org.evosuite.symbolic.solver.smt.SmtVariableCollector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Z3Solver extends SmtSolver {

	public Z3Solver() {
		super();
	}

	public Z3Solver(boolean addMissingVariables) {
		super(addMissingVariables);
	}

	static Logger logger = LoggerFactory.getLogger(Z3Solver.class);

	@Override
	public SolverResult solve(Collection> constraints) throws SolverTimeoutException, IOException,
			SolverParseException, SolverEmptyQueryException, SolverErrorException {

		long hard_timeout = Properties.DSE_CONSTRAINT_SOLVER_TIMEOUT_MILLIS;

		Set> variables = new HashSet>();
		for (Constraint c : constraints) {
			Set> c_variables = c.getVariables();
			variables.addAll(c_variables);
		}

		SmtQuery query = buildSmtQuery(constraints, hard_timeout);

		if (query.getConstantDeclarations().isEmpty()) {
			logger.debug("Z3 SMT query has no variables");
			throw new SolverEmptyQueryException("Z3 SMT query has no variables");
		}

		if (query.getAssertions().isEmpty()) {
			Map emptySolution = new HashMap();
			SolverResult emptySAT = SolverResult.newSAT(emptySolution);
			return emptySAT;
		}

		SmtQueryPrinter printer = new SmtQueryPrinter();
		String queryStr = printer.print(query);

		logger.debug("Z3 Query:");
		logger.debug(queryStr);

		if (Properties.Z3_PATH == null) {
			String errMsg = "Property Z3_PATH should be setted in order to use the Z3 Solver!";
			logger.error(errMsg);
			throw new IllegalStateException(errMsg);
		}

		String z3Cmd = Properties.Z3_PATH + " -smt2 -in ";

		ByteArrayOutputStream stdout = new ByteArrayOutputStream();
		String output;
		try {
			launchNewSolvingProcess(z3Cmd, queryStr, (int) hard_timeout, stdout);
			output = stdout.toString("UTF-8");
		} catch (SolverErrorException ex) {
			output = stdout.toString("UTF-8");
			if (!output.startsWith("unsat")) {
				throw ex;
			}
		}

		Map initialValues = getConcreteValues(variables);
		SmtModelParser parser;
		if (this.addMissingVariables()) {
			parser = new SmtModelParser(initialValues);
		} else {
			parser = new SmtModelParser();
		}

		SolverResult result = parser.parse(output);

		if (result.isSAT()) {
			// check if solution is correct, otherwise return UNSAT
			boolean check = checkSAT(constraints, result);
			if (!check) {
				logger.debug("Z3 solution fails to solve the constraint system!");
				SolverResult unsatResult = SolverResult.newUNSAT();
				return unsatResult;
			}
		}

		return result;
	}

	private final static int ASCII_TABLE_LENGTH = 90;

	private static String encodeString(String str) {
		char[] charArray = str.toCharArray();
		String ret_val = "";
		for (int i = 0; i < charArray.length; i++) {
			char c = charArray[i];
			// if (Character.isISOControl(c)) {
			if (Integer.toHexString(c).length() == 1) {
				// padding
				ret_val += "\\x0" + Integer.toHexString(c);
			} else {
				ret_val += "\\x" + Integer.toHexString(c);
			}
			// } else {
			// ret_val += c;
			// }
		}
		return ret_val;
	}

	private static String buildIntToCharFunction() {
		StringBuffer buff = new StringBuffer();
		buff.append(SmtOperation.Operator.INT_TO_CHAR + "((x!1 Int)) String");
		buff.append("\n");
		for (int i = 0; i < ASCII_TABLE_LENGTH; i++) {
			char c = (char) i;
			String str = String.valueOf(c);
			String encodedStr = encodeString(str);
			if (i < ASCII_TABLE_LENGTH - 1) {
				String iteStr = String.format("(ite (= x!1 %s) \"%s\"", i, encodedStr);
				buff.append(iteStr);
				buff.append("\n");
			} else {
				buff.append("\"" +encodedStr + "\"");
			}
		}
		for (int i = 0; i < ASCII_TABLE_LENGTH - 1; i++) {
			buff.append(")");
		}
		buff.append("\n");
		return buff.toString();
	}

	private static String buildCharToIntFunction() {
		StringBuffer buff = new StringBuffer();
		buff.append(SmtOperation.Operator.CHAR_TO_INT + "((x!1 String)) Int");
		buff.append("\n");
		for (int i = 0; i < ASCII_TABLE_LENGTH; i++) {
			char c = (char) i;
			String str = String.valueOf(c);
			String encodedStr = encodeString(str);
			if (i < ASCII_TABLE_LENGTH - 1) {
				String iteStr = String.format("(ite (= x!1 \"%s\") %s", encodedStr, i);
				buff.append(iteStr);
				buff.append("\n");
			} else {
				buff.append(i);
			}
		}
		for (int i = 0; i < ASCII_TABLE_LENGTH - 1; i++) {
			buff.append(")");
		}
		buff.append("\n");
		return buff.toString();
	}

	private static SmtQuery buildSmtQuery(Collection> constraints, long timeout) {

		SmtQuery query = new SmtQuery();

		query.addOption(":timeout", String.valueOf(timeout));

		ConstraintToZ3Visitor v = new ConstraintToZ3Visitor();

		SmtVariableCollector varCollector = new SmtVariableCollector();
		SmtOperatorCollector opCollector = new SmtOperatorCollector();

		for (Constraint c : constraints) {
			SmtExpr smtExpr = c.accept(v, null);
			if (smtExpr != null) {
				SmtAssertion smtAssertion = new SmtAssertion(smtExpr);
				query.addAssertion(smtAssertion);
				smtExpr.accept(varCollector, null);
				smtExpr.accept(opCollector, null);
			}
		}

		Set smtVariables = varCollector.getSmtVariables();
		Set smtOperators = opCollector.getOperators();

		Set smtVariablesToDeclare = new HashSet(smtVariables);

		for (SmtVariable v1 : smtVariablesToDeclare) {
			String varName = v1.getName();
			if (v1 instanceof SmtIntVariable) {
				SmtConstantDeclaration constantDecl = SmtExprBuilder.mkIntConstantDeclaration(varName);
				query.addConstantDeclaration(constantDecl);
			} else if (v1 instanceof SmtRealVariable) {
				SmtConstantDeclaration constantDecl = SmtExprBuilder.mkRealConstantDeclaration(varName);
				query.addConstantDeclaration(constantDecl);
			} else if (v1 instanceof SmtStringVariable) {
				SmtConstantDeclaration constantDecl = SmtExprBuilder.mkStringConstantDeclaration(varName);
				query.addConstantDeclaration(constantDecl);
			} else {
				throw new RuntimeException("Unknown variable type " + v1.getClass().getCanonicalName());
			}
		}

		if (smtOperators.contains(SmtOperation.Operator.CHAR_TO_INT)) {
			String charToInt = buildCharToIntFunction();
			SmtFunctionDefinition newFunctionDef = new SmtFunctionDefinition(charToInt);
			query.addFunctionDefinition(newFunctionDef);
		}

		if (smtOperators.contains(SmtOperation.Operator.INT_TO_CHAR)) {
			String intToChar = buildIntToCharFunction();
			SmtFunctionDefinition newFunctionDef = new SmtFunctionDefinition(intToChar);
			query.addFunctionDefinition(newFunctionDef);
		}

		return query;

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy