char *Z3SolverImpl::getConstraintLog(const Query &query) { std::vector<Z3ASTHandle> assumptions; // We use a different builder here because we don't want to interfere // with the solver's builder because it may change the solver builder's // cache. // NOTE: The builder does not set `z3LogInteractionFile` to avoid conflicting // with whatever the solver's builder is set to do. Z3Builder temp_builder(/*autoClearConstructCache=*/false, /*z3LogInteractionFile=*/NULL); for (std::vector<ref<Expr> >::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { assumptions.push_back(temp_builder.construct(*it)); } ::Z3_ast *assumptionsArray = NULL; int numAssumptions = query.constraints.size(); if (numAssumptions) { assumptionsArray = (::Z3_ast *)malloc(sizeof(::Z3_ast) * numAssumptions); for (int index = 0; index < numAssumptions; ++index) { assumptionsArray[index] = (::Z3_ast)assumptions[index]; } } // KLEE Queries are validity queries i.e. // ∀ X Constraints(X) → query(X) // but Z3 works in terms of satisfiability so instead we ask the // the negation of the equivalent i.e. // ∃ X Constraints(X) ∧ ¬ query(X) Z3ASTHandle formula = Z3ASTHandle( Z3_mk_not(temp_builder.ctx, temp_builder.construct(query.expr)), temp_builder.ctx); ::Z3_string result = Z3_benchmark_to_smtlib_string( temp_builder.ctx, /*name=*/"Emited by klee::Z3SolverImpl::getConstraintLog()", /*logic=*/"", /*status=*/"unknown", /*attributes=*/"", /*num_assumptions=*/numAssumptions, /*assumptions=*/assumptionsArray, /*formula=*/formula); if (numAssumptions) free(assumptionsArray); // We need to trigger a dereference before the `temp_builder` gets destroyed. // We do this indirectly by emptying `assumptions` and assigning to // `formula`. assumptions.clear(); formula = Z3ASTHandle(NULL, temp_builder.ctx); // Client is responsible for freeing the returned C-string return strdup(result); }
char *Z3SolverImpl::getConstraintLog(const Query &query) { std::vector<Z3ASTHandle> assumptions; for (std::vector<ref<Expr> >::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { assumptions.push_back(builder->construct(*it)); } ::Z3_ast *assumptionsArray = NULL; int numAssumptions = query.constraints.size(); if (numAssumptions) { assumptionsArray = (::Z3_ast *)malloc(sizeof(::Z3_ast) * numAssumptions); for (int index = 0; index < numAssumptions; ++index) { assumptionsArray[index] = (::Z3_ast)assumptions[index]; } } // KLEE Queries are validity queries i.e. // ∀ X Constraints(X) → query(X) // but Z3 works in terms of satisfiability so instead we ask the // the negation of the equivalent i.e. // ∃ X Constraints(X) ∧ ¬ query(X) Z3ASTHandle formula = Z3ASTHandle( Z3_mk_not(builder->ctx, builder->construct(query.expr)), builder->ctx); ::Z3_string result = Z3_benchmark_to_smtlib_string( builder->ctx, /*name=*/"Emited by klee::Z3SolverImpl::getConstraintLog()", /*logic=*/"", /*status=*/"unknown", /*attributes=*/"", /*num_assumptions=*/numAssumptions, /*assumptions=*/assumptionsArray, /*formula=*/formula); if (numAssumptions) free(assumptionsArray); // Client is responsible for freeing the returned C-string return strdup(result); }