mCRL2
Loading...
Searching...
No Matches
smt_lib_solver.cpp
Go to the documentation of this file.
1#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
2#include <array>
3#include <cerrno> // for errno
4#include <sys/types.h> // for pid_t
5#include <sys/wait.h> // for waitpid()
6#include <sys/ioctl.h> // for ioctl() and FIONREAD
7#include "mcrl2/data/detail/prover/smt_lib_solver.h"
8
9using namespace mcrl2::log;
10
11
12
13
14namespace mcrl2::data::detail::prover
15{
16template < typename T >
17bool binary_smt_solver< T >::execute(std::string const& benchmark)
18{
19 std::array<int, 2> pipe_stdin;
20 std::array<int, 2> pipe_stdout;
21 std::array<int, 2> pipe_stderr;
22
23 // Create pipes (two pairs r/w)
24 if (::pipe(&pipe_stdin[0]) < 0)
25 {
26 throw mcrl2::runtime_error("failed to create pipe");
27 }
28
29 if (::pipe(&pipe_stdout[0]) < 0)
30 {
31 throw mcrl2::runtime_error("failed to create pipe");
32 }
33
34 if (::pipe(&pipe_stderr[0]) < 0)
35 {
36 throw mcrl2::runtime_error("failed to create pipe");
37 }
38
39 // fork process
40 pid_t pid = ::fork();
41
42 if (pid == 0)
43 {
44 ::dup2(pipe_stdin[0], STDIN_FILENO);
45 ::dup2(pipe_stdout[1], STDOUT_FILENO);
46 ::dup2(pipe_stderr[1], STDERR_FILENO);
47
48 ::close(pipe_stdin[1]);
49 ::close(pipe_stdout[0]);
50 ::close(pipe_stderr[0]);
51
52 T::exec();
53
54 ::_exit(errno);
55 }
56 else if (pid < 0)
57 {
58 mCRL2log(log_level_t::error) << strerror(errno) << std::endl;
59
60 ::close(pipe_stdin[0]);
61 ::close(pipe_stdin[1]);
62 ::close(pipe_stdout[0]);
63 ::close(pipe_stdout[1]);
64 ::close(pipe_stderr[0]);
65 ::close(pipe_stderr[1]);
66
67 return false;
68 }
69 else
70 {
71 if(::write(pipe_stdin[1], benchmark.c_str(), benchmark.size()) < 0)
72 {
73 throw mcrl2::runtime_error("failed to write benchmark");
74 }
75
76 ::close(pipe_stdin[0]);
77 ::close(pipe_stdin[1]);
78 ::close(pipe_stdout[1]);
79 ::close(pipe_stderr[1]);
80
81 std::array<char, 64> output;
82
83 int return_status;
84
85 // check return value
86 if (0 < ::read(pipe_stdout[0], output.data(), 8))
87 {
88 if (strncmp(output.data(), "sat", 3) == 0)
89 {
90 mCRL2log(log_level_t::verbose) << "The formula is satisfiable" << std::endl;
91
92 ::close(pipe_stdout[0]);
93 ::close(pipe_stderr[0]);
94
95 ::wait(&return_status);
96
97 return true;
98 }
99 else if (strncmp(output.data(), "unsat", 5) == 0)
100 {
101 mCRL2log(log_level_t::verbose) << "The formula is unsatisfiable" << std::endl;
102 }
103 else if (strncmp(output.data(), "unknown", 7) == 0)
104 {
105 mCRL2log(log_level_t::verbose) << T::name() << " cannot determine whether this formula is satisfiable or not." << std::endl;
106 }
107 }
108 else
109 {
110 std::string message;
111
112 while (ssize_t i = ::read(pipe_stderr[0], output.data(), 64))
113 {
114 message.append(output.data(), static_cast<std::size_t>(i));
115 }
116
117 throw mcrl2::runtime_error(std::string("The SMT prover ") + T::name() + " does not work properly. " + message );
118 }
119
120 ::close(pipe_stdout[0]);
121 ::close(pipe_stderr[0]);
122
123 ::wait(&return_status);
124 }
125
126 return false;
127}
128
129/**
130 * \brief Checks the availability/usability of the prover
131 **/
132template < typename T >
133bool binary_smt_solver< T >::usable()
134{
135 if (!binary_smt_solver::execute("(benchmark nameless :formula true)"))
136 {
137 throw mcrl2::runtime_error(std::string("The SMT solver ") + T::name() + " is not available. \n" +
138 "Consult the manual of the tool you are using for instructions on how to obtain " + T::name() + ".");
139
140 return false;
141 }
142
143 return true;
144}
145
146// instantiate for cvc prover
147template class binary_smt_solver< cvc_smt_solver >;
148
149// instantiate for z3 prover
150template class binary_smt_solver< z3_smt_solver >;
151
152// instantiate for ario prover
153template class binary_smt_solver< ario_smt_solver >;
154}
155
156
157
158#endif
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435