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