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

org.evosuite.symbolic.solver.z3str2.Z3Str2Solver 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.z3str2;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.FileUtils;
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.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.SubProcessSolver;
import org.evosuite.symbolic.solver.smt.SmtAssertion;
import org.evosuite.symbolic.solver.smt.SmtCheckSatQuery;
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.SmtOperation;
import org.evosuite.symbolic.solver.smt.SmtOperation.Operator;
import org.evosuite.symbolic.solver.smt.SmtOperatorCollector;
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.evosuite.symbolic.solver.z3.Z3Solver;
import org.evosuite.testcase.execution.EvosuiteError;
import org.evosuite.utils.FileIOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Z3Str2Solver extends SubProcessSolver {

	private static final String EVOSUITE_Z3_STR_FILENAME = "evosuite.z3";

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

	private static int dirCounter = 0;

	public Z3Str2Solver() {
		super();
	}

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

	private static File createNewTmpDir() {
		File dir = null;
		String dirName = FileUtils.getTempDirectoryPath() + File.separator + "EvoSuiteZ3Str_" + (dirCounter++) + "_"
				+ System.currentTimeMillis();

		// first create a tmp folder
		dir = new File(dirName);
		if (!dir.mkdirs()) {
			logger.error("Cannot create tmp dir: " + dirName);
			return null;
		}

		if (!dir.exists()) {
			logger.error(
					"Weird behavior: we created folder, but Java cannot determine if it exists? Folder: " + dirName);
			return null;
		}

		return dir;
	}

	private static SmtCheckSatQuery buildSmtQuerty(Collection> constraints) {

		ConstraintToZ3Str2Visitor v = new ConstraintToZ3Str2Visitor();
		List assertions = new LinkedList();

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

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

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

		boolean addCharToIntFunction;
		if (smtOperators.contains(SmtOperation.Operator.CHAR_TO_INT)) {
			addCharToIntFunction = true;
		} else {
			addCharToIntFunction = false;
		}

		Set smtVariablesToDeclare = new HashSet(smtVariables);
		if (addCharToIntFunction) {
			Set charVariables = buildCharVariables();
			smtVariablesToDeclare.addAll(charVariables);
		}

		List constantDeclarations = new LinkedList();

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

		List functionDefinitions = new LinkedList();
		if (addCharToIntFunction) {
			String charToInt = buildCharToIntFunction();
			SmtFunctionDefinition newFunctionDef = new SmtFunctionDefinition(charToInt);
			functionDefinitions.add(newFunctionDef);
		}

		SmtCheckSatQuery smtCheckSatQuery = new SmtCheckSatQuery(constantDeclarations, functionDefinitions, assertions);

		return smtCheckSatQuery;

	}

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

		SmtCheckSatQuery smtCheckSatQuery = buildSmtQuerty(constraints);

		if (smtCheckSatQuery.getConstantDeclarations().isEmpty()) {
			logger.debug("Z3-str2 input has no variables");
			throw new SolverEmptyQueryException("Z3-str2 input has no variables");
		}

		if (smtCheckSatQuery.getAssertions().isEmpty()) {
			Map emptySolution = new HashMap();
			SolverResult emptySAT = SolverResult.newSAT(emptySolution);
			return emptySAT;
		}
		
		Z3Str2QueryPrinter printer = new Z3Str2QueryPrinter();
		String smtQueryStr = printer.print(smtCheckSatQuery);

		logger.debug("Z3-str2 input:");
		logger.debug(smtQueryStr);

		int timeout = (int) Properties.DSE_CONSTRAINT_SOLVER_TIMEOUT_MILLIS;

		File tempDir = createNewTmpDir();
		String z3TempFileName = tempDir.getAbsolutePath() + File.separatorChar + EVOSUITE_Z3_STR_FILENAME;

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

		try {
			FileIOUtils.writeFile(smtQueryStr, z3TempFileName);
			String z3Cmd = Properties.Z3_STR2_PATH + " -f " + z3TempFileName;
			ByteArrayOutputStream stdout = new ByteArrayOutputStream();
			launchNewProcess(z3Cmd, smtQueryStr, timeout, stdout);

			String z3str2ResultStr = stdout.toString("UTF-8");

			Z3Str2ResultParser parser = new Z3Str2ResultParser();
			Set> variables = getVariables(constraints);
			Map initialValues = getConcreteValues(variables);
			SolverResult solverResult;
			if (addMissingVariables()) {
				solverResult = parser.parse(z3str2ResultStr, initialValues);
			} else {
				solverResult = parser.parse(z3str2ResultStr);
			}

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

			return solverResult;

		} catch (UnsupportedEncodingException e) {
			throw new EvosuiteError("UTF-8 should not cause this exception!");
		} finally {
			File tempFile = new File(z3TempFileName);
			if (tempFile.exists()) {
				tempFile.delete();
			}
		}
	}

	private final static int ASCII_TABLE_LENGTH = 90;

	private static Set buildCharVariables() {
		Set charVariables = new HashSet();

		for (int i = 0; i < ASCII_TABLE_LENGTH; i++) {
			char c = (char) i;
			String str = String.valueOf(c);
			String encodedStr = ExprToZ3Str2Visitor.encodeString(str);
			SmtStringVariable v = new SmtStringVariable(encodedStr);
			charVariables.add(v);
		}
		return charVariables;
	}

	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 = ExprToZ3Str2Visitor.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();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy