Skip to content

Commit 5e037da

Browse files
author
Leo Alt
committed
Fix smtchecker callback tests and add Eldarica
1 parent ee86329 commit 5e037da

File tree

4 files changed

+42
-21
lines changed

4 files changed

+42
-21
lines changed

smtchecker.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ function handleSMTQueries (inputJSON, outputJSON, solver) {
2525
return inputJSON;
2626
}
2727

28-
function smtCallback (solver) {
28+
function smtCallback (solverFunction, solver) {
2929
return function (query) {
3030
try {
31-
var result = solver(query);
31+
var result = solverFunction(query, solver);
3232
return { contents: result };
3333
} catch (err) {
3434
return { error: err };

smtsolver.js

+21-12
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,43 @@ var execSync = require('child_process').execSync;
33
var fs = require('fs');
44
var tmp = require('tmp');
55

6+
// Timeout in ms.
67
const timeout = 10000;
78

89
var potentialSolvers = [
910
{
1011
name: 'z3',
12+
command: 'z3',
1113
params: '-smt2 rlimit=20000000 rewriter.pull_cheap_ite=true fp.spacer.q3.use_qgen=true fp.spacer.mbqi=false fp.spacer.ground_pobs=false'
1214
},
15+
{
16+
name: 'Eldarica',
17+
command: 'eld',
18+
params: '-horn -t:' + (timeout / 1000)
19+
},
1320
{
1421
name: 'cvc4',
22+
command: 'cvc4',
1523
params: '--lang=smt2 --tlimit=' + timeout
1624
}
1725
];
18-
var solvers = potentialSolvers.filter(solver => commandExistsSync(solver.name));
26+
var solvers = potentialSolvers.filter(solver => commandExistsSync(solver.command));
1927

20-
function solve (query) {
21-
if (solvers.length === 0) {
22-
throw new Error('No SMT solver available. Assertion checking will not be performed.');
28+
function solve (query, solver) {
29+
if (solver === undefined) {
30+
if (solvers.length === 0) {
31+
throw new Error('No SMT solver available. Assertion checking will not be performed.');
32+
} else {
33+
solver = solvers[0];
34+
}
2335
}
2436

2537
var tmpFile = tmp.fileSync({ postfix: '.smt2' });
2638
fs.writeFileSync(tmpFile.name, query);
27-
// TODO For now only the first SMT solver found is used.
28-
// At some point a computation similar to the one done in
29-
// SMTPortfolio::check should be performed, where the results
30-
// given by different solvers are compared and an error is
31-
// reported if solvers disagree (i.e. SAT vs UNSAT).
3239
var solverOutput;
3340
try {
3441
solverOutput = execSync(
35-
solvers[0].name + ' ' + solvers[0].params + ' ' + tmpFile.name, {
42+
solver.command + ' ' + solver.params + ' ' + tmpFile.name, {
3643
stdio: 'pipe'
3744
}
3845
).toString();
@@ -44,7 +51,9 @@ function solve (query) {
4451
if (
4552
!solverOutput.startsWith('sat') &&
4653
!solverOutput.startsWith('unsat') &&
47-
!solverOutput.startsWith('unknown')
54+
!solverOutput.startsWith('unknown') &&
55+
!solverOutput.startsWith('(error') &&
56+
!solverOutput.startsWith('error')
4857
) {
4958
throw new Error('Failed to solve SMT query. ' + e.toString());
5059
}
@@ -56,5 +65,5 @@ function solve (query) {
5665

5766
module.exports = {
5867
smtSolver: solve,
59-
availableSolvers: solvers.length
68+
availableSolvers: solvers
6069
};

test/smtCheckerTests/loop.sol

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
contract C {
2+
function f(uint x) public pure {
3+
uint i = 0;
4+
while (i < x)
5+
++i;
6+
assert(i == x);
7+
}
8+
}

test/smtcallback.js

+11-7
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,10 @@ tape('SMTCheckerCallback', function (t) {
132132
return;
133133
}
134134

135-
if (smtsolver.availableSolvers === 0) {
136-
st.skip('No SMT solver available.');
135+
// For these tests we actually need z3/Spacer.
136+
const z3HornSolvers = smtsolver.availableSolvers.filter(solver => solver.command === 'z3');
137+
if (z3HornSolvers.length === 0) {
138+
st.skip('z3/Spacer not available.');
137139
st.end();
138140
return;
139141
}
@@ -167,9 +169,8 @@ tape('SMTCheckerCallback', function (t) {
167169
if (source.includes(option)) {
168170
let idx = source.indexOf(option);
169171
if (source.indexOf(option, idx + 1) !== -1) {
170-
st.skip('SMTEngine option given multiple times.');
171-
st.end();
172-
return;
172+
st.comment('SMTEngine option given multiple times.');
173+
continue;
173174
}
174175
let re = new RegExp(option + '(\\w+)');
175176
let m = source.match(re);
@@ -211,15 +212,18 @@ tape('SMTCheckerCallback', function (t) {
211212
// `pragma experimental SMTChecker;` was deprecated in 0.8.4
212213
if (semver.gt(solc.semver(), '0.8.3')) {
213214
let engine = test.engine !== undefined ? test.engine : 'all';
214-
settings = { modelChecker: { engine: engine } };
215+
settings = { modelChecker: {
216+
engine: engine,
217+
solvers: [ 'smtlib2' ]
218+
} };
215219
}
216220
var output = JSON.parse(solc.compile(
217221
JSON.stringify({
218222
language: 'Solidity',
219223
sources: test.solidity,
220224
settings: settings
221225
}),
222-
{ smtSolver: smtchecker.smtCallback(smtsolver.smtSolver) }
226+
{ smtSolver: smtchecker.smtCallback(smtsolver.smtSolver, z3HornSolvers[0]) }
223227
));
224228
st.ok(output);
225229

0 commit comments

Comments
 (0)