1 /*
2 This file is part of solidity.
3
4 solidity is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 solidity is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with solidity. If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18
19 #include <test/libsolidity/SMTCheckerTest.h>
20 #include <test/Common.h>
21
22 #include <range/v3/action/remove_if.hpp>
23
24 using namespace std;
25 using namespace solidity;
26 using namespace solidity::langutil;
27 using namespace solidity::frontend;
28 using namespace solidity::frontend::test;
29
SMTCheckerTest(string const & _filename)30 SMTCheckerTest::SMTCheckerTest(string const& _filename): SyntaxTest(_filename, EVMVersion{})
31 {
32 auto const& showUnproved = m_reader.stringSetting("SMTShowUnproved", "yes");
33 if (showUnproved == "no")
34 m_modelCheckerSettings.showUnproved = false;
35 else if (showUnproved == "yes")
36 m_modelCheckerSettings.showUnproved = true;
37 else
38 BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT \"show unproved\" choice."));
39
40 m_modelCheckerSettings.solvers = smtutil::SMTSolverChoice::None();
41 auto const& choice = m_reader.stringSetting("SMTSolvers", "any");
42 if (choice == "any")
43 m_modelCheckerSettings.solvers = smtutil::SMTSolverChoice::All();
44 else if (choice == "none")
45 m_modelCheckerSettings.solvers = smtutil::SMTSolverChoice::None();
46 else if (!m_modelCheckerSettings.solvers.setSolver(choice))
47 BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT solver choice."));
48
49 m_modelCheckerSettings.solvers &= ModelChecker::availableSolvers();
50
51 /// Underflow and Overflow are not enabled by default for Solidity >=0.8.7,
52 /// so we explicitly enable all targets for the tests.
53 m_modelCheckerSettings.targets = ModelCheckerTargets::All();
54
55 auto engine = ModelCheckerEngine::fromString(m_reader.stringSetting("SMTEngine", "all"));
56 if (engine)
57 m_modelCheckerSettings.engine = *engine;
58 else
59 BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT engine choice."));
60
61 if (m_modelCheckerSettings.solvers.none() || m_modelCheckerSettings.engine.none())
62 m_shouldRun = false;
63
64 auto const& ignoreCex = m_reader.stringSetting("SMTIgnoreCex", "no");
65 if (ignoreCex == "no")
66 m_ignoreCex = false;
67 else if (ignoreCex == "yes")
68 m_ignoreCex = true;
69 else
70 BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT counterexample choice."));
71
72 auto const& ignoreInv = m_reader.stringSetting("SMTIgnoreInv", "no");
73 if (ignoreInv == "no")
74 m_modelCheckerSettings.invariants = ModelCheckerInvariants::All();
75 else if (ignoreInv == "yes")
76 m_modelCheckerSettings.invariants = ModelCheckerInvariants::None();
77 else
78 BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT invariant choice."));
79
80 auto const& ignoreOSSetting = m_reader.stringSetting("SMTIgnoreOS", "none");
81 for (string const& os: ignoreOSSetting | ranges::views::split(',') | ranges::to<vector<string>>())
82 {
83 #ifdef __APPLE__
84 if (os == "macos")
85 m_shouldRun = false;
86 #elif _WIN32
87 if (os == "windows")
88 m_shouldRun = false;
89 #elif __linux__
90 if (os == "linux")
91 m_shouldRun = false;
92 #endif
93 }
94 }
95
run(ostream & _stream,string const & _linePrefix,bool _formatted)96 TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
97 {
98 setupCompiler();
99 compiler().setModelCheckerSettings(m_modelCheckerSettings);
100 parseAndAnalyze();
101 filterObtainedErrors();
102
103 return conclude(_stream, _linePrefix, _formatted);
104 }
105
filterObtainedErrors()106 void SMTCheckerTest::filterObtainedErrors()
107 {
108 SyntaxTest::filterObtainedErrors();
109
110 static auto removeCex = [](vector<SyntaxTestError>& errors) {
111 for (auto& e: errors)
112 if (
113 auto cexPos = e.message.find("\\nCounterexample");
114 cexPos != string::npos
115 )
116 e.message = e.message.substr(0, cexPos);
117 };
118
119 if (m_ignoreCex)
120 removeCex(m_errorList);
121 }
122