예제 #1
0
        /// <summary>
        /// Returns a SMT-LIB v2.0-compliant string that corresponds to
        /// the input Boolean Expression.
        /// </summary>
        ///
        /// <param name="expr">Boolean Expression.</param>
        /// <returns>SMT-LIB v2.0-compliant string that corresponds to
        /// the input Boolean Expression.</returns>
        private static string MakeBooleanExpr(Expression expr)
        {
            string       result     = null;
            OperatorType exprOpType = expr.Op.Type;

            switch (exprOpType)
            {
            case OperatorType.And:
            case OperatorType.Or:
                Expression firstExpr  = expr.GetParameter(0);
                Expression secondExpr = expr.GetParameter(1);

                Pair <string, ExpressionType> convertedFirstExpr =
                    SmtHelper.ConvertToSmtLib2(firstExpr);
                Pair <string, ExpressionType> convertedSecondExpr =
                    SmtHelper.ConvertToSmtLib2(secondExpr);
                result = "(" + ((exprOpType == OperatorType.And) ? "and" : "or") +
                         " " + convertedFirstExpr.First + " " + convertedSecondExpr.First + ")";
                break;

            case OperatorType.Not:
                Expression toNotExpr = expr.GetParameter(0);
                Pair <string, ExpressionType> convertToNotExpr =
                    SmtHelper.ConvertToSmtLib2(toNotExpr);
                result = "(not " + convertToNotExpr.First + ")";
                break;
            }

            Trace.Assert(result != null,
                         "PHOENIX: Could not convert Boolean Expression: " + expr.ToString());
            return(result);
        }
예제 #2
0
        /// <summary>
        /// Returns a string that complies with the SMT-LIB v2.0 standard and that corresponds
        /// to a query that checks the feasibility of the conditions along the input Path.
        /// </summary>
        ///
        /// <param name="path">Path to convert.</param>
        /// <returns>String that complies with the SMT-LIB v2.0 standard and that corresponds to
        /// a query that checks the feasibility of the conditions along the input Path.</returns>
        public static string ConvertToSmtLib2Query(Path path)
        {
            string result = "";

            /* Add the command to initialize the solver with the QF_AUFBV logic. */
            result += "(set-logic QF_AUFBV)" + "\n";

            /* Add declarations for the Boolean constraint variables. */
            string identConstraint = path.Config.IDENT_CONSTRAINT;
            uint   constraintNum;

            for (constraintNum = 0; constraintNum < path.Conditions.Count; constraintNum++)
            {
                result += "(declare-fun ";
                result += identConstraint + constraintNum.ToString() + " ";
                result += "() Bool)" + "\n";
            }

            /* Add declarations for the variables. */
            foreach (Expression varExpr in path.Variables)
            {
                result += MakeVariableBv(varExpr.Value, varExpr.BitSize) + "\n";
            }

            /* Add declarations for the array variables. */
            foreach (Expression arrayVarExpr in path.ArrayVariables)
            {
                result += MakeArrayVarBv(arrayVarExpr.Value,
                                         path.ArrayDimensions[arrayVarExpr], path) + "\n";
            }

            /* Assert the conditions along the input Path. */
            constraintNum = 0;
            foreach (Pair <Expression, uint> conditionPair in path.Conditions)
            {
                Pair <string, ExpressionType> convertedCondition =
                    SmtHelper.ConvertToSmtLib2(conditionPair.First);
                result += "(assert (= ";
                result += identConstraint + constraintNum.ToString() + " ";
                result += convertedCondition.First + "))" + "\n";
                constraintNum++;
            }

            /* Assert that the Boolean constraint variables are all true. */
            result += "(assert (and";
            for (constraintNum = 0; constraintNum < path.Conditions.Count; constraintNum++)
            {
                result += " " + identConstraint + constraintNum.ToString();
            }
            result += "))" + "\n";

            /* Finish the query. */
            result += "(check-sat)" + "\n";
            result += "(exit)" + "\n";
            return(result);
        }
예제 #3
0
        /// <summary>
        /// Returns a SMT-LIB v2.0-compliant string that corresponds to the sort of an array of
        /// bitvectors with bitvector indices, having the input dimensions.
        /// </summary>
        ///
        /// <param name="dimensions">Dimensions of an array of bitvectors with
        /// bitvector indices.</param>
        /// <param name="path">Path that contains the input array
        /// whose dimensions are provided.</param>
        /// <returns>SMT-LIB v2.0-compliant string that corresponds to the sort of an array of
        /// bitvectors with bitvector indices, having the input dimensions.</returns>
        private static string MakeArraySort(List <uint> dimensions, Path path)
        {
            string result = "(Array";

            if (!path.ProjectConfig.MODEL_AS_NESTED_ARRAYS)
            {
                long sumDomainDims = dimensions.GetRange(0, dimensions.Count - 1).Sum(dim => dim);
                result += " " + SmtHelper.MakeBvSort(sumDomainDims) + " ";
                result += SmtHelper.MakeBvSort(dimensions[dimensions.Count - 1]) + ")";
                return(result);
            }

            if (dimensions.Count == 1)
            {
                return(SmtHelper.MakeBvSort(dimensions[0]));
            }

            result += " " + SmtHelper.MakeBvSort(dimensions[0]) + " ";
            result += SmtHelper.MakeArraySort(dimensions.GetRange(1, dimensions.Count - 1), path);
            result  = result.TrimEnd() + ")";
            return(result);
        }
예제 #4
0
        /// <summary>
        /// Converts a Boolean Expression into a logically equivalent ITE statement that returns
        /// a bitvector instead. If the Expression is not Boolean, it is returned unchanged.
        /// </summary>
        ///
        /// <param name="exprString">SMT-LIB v2.0-compliant string that represents
        /// the Expression to convert.</param>
        /// <param name="exprType">Type of the Expression.</param>
        /// <param name="bitSize">Bit-size of the resulting bitvector.</param>
        /// <returns>Logically equivalent ITE statement if the Expression is Boolean;
        /// unchanged input Expression otherwise.</returns>
        private static string BooleanToIte(string exprString,
                                           ExpressionType exprType, uint bitSize)
        {
            string result = null;

            switch (exprType)
            {
            case ExpressionType.DEFAULT:
                result = exprString;
                break;

            case ExpressionType.BOOLEAN:
                string zeroBv = SmtHelper.MakeConstantBv("0", bitSize);
                string oneBv  = SmtHelper.MakeConstantBv("1", bitSize);
                result = "(ite " + exprString + " " + oneBv + " " + zeroBv + ")";
                break;

            default:
                Trace.Fail("PHOENIX: Unrecognized Expression type: " + exprType.ToString());
                break;
            }

            return(result);
        }
예제 #5
0
        /// <summary>
        /// Returns a pair whose first element is a string that complies with the SMT-LIB v2.0
        /// standard and that corresponds to the input Expression, and whose second element
        /// is the type of the Expression.
        /// </summary>
        ///
        /// <param name="expr">Expression to convert.</param>
        /// <returns>Pair whose first element is a string that complies with the SMT-LIB v2.0
        /// standard and that corresponds to the input Expression, and whose second element
        /// is the type of the Expression.</returns>
        private static Pair <string, ExpressionType> ConvertToSmtLib2(Expression expr)
        {
            Pair <string, ExpressionType> result = null;
            string resultString = "";

            OperatorType exprOpType = expr.Op.Type;

            switch (exprOpType)
            {
            case OperatorType.True:
                result = new Pair <string, ExpressionType>("true", ExpressionType.BOOLEAN);
                break;

            case OperatorType.False:
                result = new Pair <string, ExpressionType>("false", ExpressionType.BOOLEAN);
                break;

            case OperatorType.Constant:
                resultString = SmtHelper.MakeConstantBv(expr.Value, expr.BitSize);
                result       = new Pair <string, ExpressionType>(resultString, ExpressionType.DEFAULT);
                break;

            case OperatorType.Variable:
            case OperatorType.ArrayVariable:
                result = new Pair <string, ExpressionType>(expr.Value, ExpressionType.DEFAULT);
                break;

            case OperatorType.ZeroExtend:
            case OperatorType.SignExtend:
                Expression toExtendExpr = expr.GetParameter(0);
                Expression extendByExpr = expr.GetParameter(1);

                Pair <string, ExpressionType> convertedToExtendExpr =
                    SmtHelper.ConvertToSmtLib2(toExtendExpr);
                resultString = "((_ " +
                               (exprOpType == OperatorType.ZeroExtend ? "zero_extend" : "sign_extend") +
                               " " + extendByExpr.Value + ") ";
                resultString += SmtHelper.BooleanToIte(convertedToExtendExpr.First,
                                                       convertedToExtendExpr.Second, toExtendExpr.BitSize) + ")";
                result =
                    new Pair <string, ExpressionType>(resultString, ExpressionType.DEFAULT);
                break;

            case OperatorType.BitExtract:
                Expression toExtractExpr = expr.GetParameter(0);
                Expression lowIndexExpr  = expr.GetParameter(1);
                Expression highIndexExpr = expr.GetParameter(2);

                Pair <string, ExpressionType> convertedToExtractExpr =
                    SmtHelper.ConvertToSmtLib2(toExtractExpr);
                resultString = "((_ extract " + highIndexExpr.Value + " " +
                               lowIndexExpr.Value + ") ";
                resultString += SmtHelper.BooleanToIte(convertedToExtractExpr.First,
                                                       convertedToExtractExpr.Second, toExtractExpr.BitSize) + ")";
                result =
                    new Pair <string, ExpressionType>(resultString, ExpressionType.DEFAULT);
                break;

            case OperatorType.Ite:
                Expression conditionalExpr = expr.GetParameter(0);
                Expression consequentExpr  = expr.GetParameter(1);
                Expression alternateExpr   = expr.GetParameter(2);

                Pair <string, ExpressionType> convertedConditionalExpr =
                    SmtHelper.ConvertToSmtLib2(conditionalExpr);
                Pair <string, ExpressionType> convertedConsequentExpr =
                    SmtHelper.ConvertToSmtLib2(consequentExpr);
                Pair <string, ExpressionType> convertedAlternateExpr =
                    SmtHelper.ConvertToSmtLib2(alternateExpr);

                resultString  = "(ite " + convertedConditionalExpr.First + " ";
                resultString += SmtHelper.BooleanToIte(convertedConsequentExpr.First,
                                                       convertedConsequentExpr.Second, consequentExpr.BitSize) + " ";
                resultString += SmtHelper.BooleanToIte(convertedAlternateExpr.First,
                                                       convertedAlternateExpr.Second, alternateExpr.BitSize) + ")";
                result =
                    new Pair <string, ExpressionType>(resultString, ExpressionType.DEFAULT);
                break;

            case OperatorType.And:
            case OperatorType.Or:
            case OperatorType.Not:
                resultString = SmtHelper.MakeBooleanExpr(expr);
                result       =
                    new Pair <string, ExpressionType>(resultString, ExpressionType.BOOLEAN);
                break;

            case OperatorType.NotEqual:
                Expression firstParam  = expr.GetParameter(0);
                Expression secondParam = expr.GetParameter(1);

                Pair <string, ExpressionType> convertedFirstParam =
                    SmtHelper.ConvertToSmtLib2(firstParam);
                Pair <string, ExpressionType> convertedSecondParam =
                    SmtHelper.ConvertToSmtLib2(secondParam);

                resultString  = "(not (= ";
                resultString += SmtHelper.BooleanToIte(convertedFirstParam.First,
                                                       convertedFirstParam.Second, firstParam.BitSize) + " ";
                resultString += SmtHelper.BooleanToIte(convertedSecondParam.First,
                                                       convertedSecondParam.Second, secondParam.BitSize) + "))";
                result =
                    new Pair <string, ExpressionType>(resultString, ExpressionType.BOOLEAN);
                break;

            default:
                string convertedParams = "";
                foreach (Expression paramExpr in expr.ParameterList)
                {
                    Pair <string, ExpressionType> convertedParam =
                        SmtHelper.ConvertToSmtLib2(paramExpr);
                    convertedParams += " " + SmtHelper.BooleanToIte(convertedParam.First,
                                                                    convertedParam.Second, paramExpr.BitSize);
                }

                OperatorType   opType     = expr.Op.Type;
                ExpressionType resultType = SmtHelper.IsComparisonOp(opType) ?
                                            ExpressionType.BOOLEAN : ExpressionType.DEFAULT;
                string functionForOp = "";

                int numParams = expr.ParameterList.Count;
                switch (numParams)
                {
                case 1:
                    functionForOp = SmtHelper.GetFunctionForUnary(opType);
                    break;

                case 2:
                    functionForOp = SmtHelper.GetFunctionForBinary(opType);
                    break;

                case 3:
                    functionForOp = SmtHelper.GetFunctionForTernary(opType);
                    break;

                default:
                    throw new NotImplementedException("PHOENIX: " +
                                                      "No support for operators with arity " +
                                                      numParams.ToString() + ".");
                }

                resultString = "(" + functionForOp + convertedParams + ")";
                result       = new Pair <string, ExpressionType>(resultString, resultType);
                break;
            }

            Trace.Assert(result != null, "PHOENIX: Result should not be null.");
            return(result);
        }
예제 #6
0
 /// <summary>
 /// Returns a SMT-LIB v2.0-compliant string that declares the input array variable name
 /// as an array of bitvectors with bitvector indices.
 /// </summary>
 ///
 /// <param name="name">Array variable name.</param>
 /// <param name="dimensions">Dimensions of the array with the input name.</param>
 /// <param name="path">Path that contains the array with the input name.</param>
 /// <returns>SMT-LIB v2.0-compliant string that declares the input array variable name
 /// as an array of bitvectors with bitvector indices.</returns>
 private static string MakeArrayVarBv(string name, List <uint> dimensions, Path path)
 {
     return("(declare-fun " + name + " () " +
            SmtHelper.MakeArraySort(dimensions, path) + ")");
 }
예제 #7
0
        /// <summary>
        /// Finds the conditions along a path.
        /// </summary>
        ///
        /// <param name="functionUnit">Phoenix function unit.</param>
        /// <param name="config">Configuration object that contains GameTime
        /// configuration information.</param>
        /// <param name="projectConfig">ProjectConfiguration object that
        /// contains project configuration information.</param>
        public static void FindPathConditions(Phx.FunctionUnit functionUnit,
                                              Utilities.Configuration config, ProjectConfiguration projectConfig)
        {
            Console.Out.WriteLine("PHOENIX: Finding the conditions and " +
                                  "assignments along a path...");

            Console.Out.WriteLine("PHOENIX: Reading in the DAG...");

            /* Read in the DAG and deduce associated information. The DAG is in DOT file format. */
            string dagFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG);
            TextReader dagReader = new StreamReader(dagFileName);

            /* Ignore the first line. */
            dagReader.ReadLine();
            /* Read in the nodes and the edges of the graph. */
            HashSet <string> dagNodes = new HashSet <string>();
            HashSet <Pair <string, string> > dagEdges = new HashSet <Pair <string, string> >();
            string dagEdge = null;

            while ((dagEdge = dagReader.ReadLine()) != null)
            {
                dagEdge = dagEdge.Replace("{", "");
                dagEdge = dagEdge.Replace("}", "");
                dagEdge.Trim();
                if (dagEdge.Length != 0)
                {
                    /* Ignore the semicolon. */
                    dagEdge = dagEdge.Trim(';');
                    /* Split at the arrow. */
                    dagEdge = dagEdge.Replace("->", ">");
                    string[] edgeNodes = dagEdge.Split('>');
                    /* Find the nodes incident to the edge. */
                    edgeNodes[0] = edgeNodes[0].Trim();
                    edgeNodes[1] = edgeNodes[1].Trim();
                    /* Add the nodes and the edge. */
                    dagNodes.Add(edgeNodes[0]);
                    dagNodes.Add(edgeNodes[1]);
                    dagEdges.Add(new Pair <string, string>(edgeNodes[0], edgeNodes[1]));
                }
            }

            dagReader.Close();

            uint numNodes = (uint)dagNodes.Count;
            uint numEdges = (uint)dagEdges.Count;

            Console.Out.WriteLine("PHOENIX: DAG has " + numNodes + " nodes and " +
                                  numEdges + " edges.");
            Console.Out.WriteLine("PHOENIX: There are at most " +
                                  (numEdges - numNodes + 2) + " basis paths.");

            /* How many nodes are there in the original DAG, without the fake
             * intermediate nodes? */
            uint actualNumNodes = (numNodes / 2);
            uint actualNumEdges = (numEdges - actualNumNodes - 1);

            /* Get the successors of the nodes that existed in the
             * original DAG (without the fake intermediate nodes). */
            Dictionary <uint, uint> nodeSuccessors = new Dictionary <uint, uint>();

            foreach (Pair <string, string> edge in dagEdges)
            {
                uint sourceNodeId = Convert.ToUInt32(edge.First);
                uint sinkNodeId   = Convert.ToUInt32(edge.Second);

                /* Yes, there can be more than one successor for any given node.
                 * However, we are guaranteed that for the nodes in the original
                 * DAG, there is exactly one (fake) successor node. We are only
                 * concerned about these nodes. There is no great way to programatically
                 * determine these successor nodes. */
                if (sourceNodeId <= actualNumNodes)
                {
                    nodeSuccessors.Add(sourceNodeId, sinkNodeId);
                }
            }

            Console.Out.WriteLine("PHOENIX: Finished reading and processing the DAG.");

            Console.Out.WriteLine("PHOENIX: Reading the block ID map...");

            /* Read and store the mapping between "adjusted" block IDs and "actual"
             * block IDs. Also, store the reverse mapping for quick conversion
             * in the other direction. */
            Dictionary <uint, uint> adjustedToActual = new Dictionary <uint, uint>();
            Dictionary <uint, uint> actualToAdjusted = new Dictionary <uint, uint>();

            string idMapFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_DAG_ID_MAP);

            string[] idMappings = File.ReadAllLines(idMapFileName);
            foreach (string idMapping in idMappings)
            {
                string[] idMappingArray = idMapping.Split(' ');

                uint adjustedBlockId = Convert.ToUInt32(idMappingArray[0]);
                uint actualBlockId   = Convert.ToUInt32(idMappingArray[1]);

                adjustedToActual.Add(adjustedBlockId, actualBlockId);
                actualToAdjusted.Add(actualBlockId, adjustedBlockId);
            }

            Console.Out.WriteLine("PHOENIX: Finished reading and processing the ID map.");
            Console.Out.WriteLine();

            Console.Out.WriteLine("PHOENIX: Reading in the candidate path...");

            /* Read in the candidate path. */
            string pathNodesFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_NODES);
            TextReader pathNodesReader = new StreamReader(pathNodesFileName);

            string[] pathNodesArray = pathNodesReader.ReadLine().Split(' ');
            pathNodesReader.Close();

            List <uint> pathNodes = new List <uint>();

            foreach (string pathNode in pathNodesArray)
            {
                if (pathNode != "")
                {
                    pathNodes.Add(Convert.ToUInt32(pathNode));
                }
            }

            /* Convert the adjusted block IDs in the candidate path to the actual block IDs. */
            Phx.Graphs.FlowGraph         flowGraph  = functionUnit.FlowGraph;
            List <Phx.Graphs.BasicBlock> pathBlocks = new List <Phx.Graphs.BasicBlock>();
            int position = 0;

            while (position < pathNodes.Count)
            {
                uint adjustedBlockId = pathNodes[position];
                uint actualBlockId   = adjustedToActual[adjustedBlockId];

                Phx.Graphs.BasicBlock actualBlock =
                    flowGraph.Node(actualBlockId) as Phx.Graphs.BasicBlock;
                pathBlocks.Add(actualBlock);

                /* Skip over the "fake" intermediate nodes. */
                position = position + 2;
            }

            Path path = new Path(pathBlocks, config, projectConfig);

            Console.Out.WriteLine("PHOENIX: Finished reading and processing the candidate path.");

            /* Generate the conditions and the assignments along the path. */
            Console.Out.WriteLine("PHOENIX: Generating the conditions and " +
                                  "assignments along the path...");
            Console.Out.WriteLine();
            path.GenerateConditionsAndAssignments();
            Console.Out.WriteLine("PHOENIX: Finished generating the conditions and assignments.");

            if (path.ProjectConfig.debugConfig.DUMP_PATH)
            {
                path.Dump();
                Console.Out.WriteLine();
            }

            List <Pair <Expression, uint> >       conditions      = path.Conditions;
            HashSet <Expression>                  arrayVariables  = path.ArrayVariables;
            Dictionary <Expression, List <uint> > arrayDimensions = path.ArrayDimensions;

            Console.Out.WriteLine("PHOENIX: Writing information about the path " +
                                  "to temporary files...");

            Console.Out.WriteLine("PHOENIX: Writing the conditions and assignments...");

            string pathConditionsFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_CONDITIONS);
            StreamWriter pathConditionsWriter = new StreamWriter(pathConditionsFileName, false);

            pathConditionsWriter.AutoFlush = true;

            List <Expression> conditionExprs = new List <Expression>();

            foreach (Pair <Expression, uint> conditionPair in conditions)
            {
                Expression condition = conditionPair.First;
                pathConditionsWriter.WriteLine(condition);
                conditionExprs.Add(condition);
            }

            pathConditionsWriter.Close();

            Console.Out.WriteLine("PHOENIX: Writing completed.");

            Console.Out.WriteLine("PHOENIX: Writing line numbers...");
            path.DumpLineNumbers();
            Console.Out.WriteLine("PHOENIX: Writing completed.");

            Console.Out.WriteLine("PHOENIX: Writing the edges that correspond to " +
                                  "conditions and assignments...");

            /* The actual source node that corresponds to a constraint (condition
            * or assignment) is the dummy node after the adjusted source node. */
            path.DumpConditionEdges(sourceNodeId => nodeSuccessors[actualToAdjusted[sourceNodeId]],
                                    sinkNodeId => actualToAdjusted[sinkNodeId]);
            Console.Out.WriteLine("PHOENIX: Writing completed.");

            Console.Out.WriteLine("PHOENIX: Writing the line numbers and truth values of " +
                                  "the conditional points..");
            path.DumpConditionTruths();
            Console.Out.WriteLine("PHOENIX: Writing completed.");

            Console.Out.WriteLine("PHOENIX: Writing information about array and " +
                                  "aggregate accesses...");
            path.DumpAccesses();
            Console.Out.WriteLine("PHOENIX: Writing completed.");

            if (path.ProjectConfig.debugConfig.DUMP_ALL_PATHS)
            {
                string allPathsFileName =
                    System.IO.Path.Combine(projectConfig.locationTempDir, config.TEMP_PATH_ALL);
                StreamWriter allPathsWriter = new StreamWriter(allPathsFileName, true);
                allPathsWriter.AutoFlush = true;
                allPathsWriter.Write("*** CANDIDATE PATH ***");
                allPathsWriter.WriteLine(path.ToString());
                allPathsWriter.Close();
            }

            Console.Out.WriteLine("PHOENIX: Path information written to temporary files.");

            Console.Out.WriteLine("PHOENIX: Writing the corresponding SMT query to " +
                                  "a temporary file...");

            string smtQueryFileName =
                System.IO.Path.Combine(projectConfig.locationTempDir,
                                       config.TEMP_PATH_QUERY + ".smt");
            StreamWriter smtQueryWriter = new StreamWriter(smtQueryFileName, false);

            smtQueryWriter.AutoFlush = true;
            smtQueryWriter.Write(SmtHelper.ConvertToSmtLib2Query(path));
            smtQueryWriter.Close();

            Console.Out.WriteLine("PHOENIX: Writing completed.");
        }