Skip to content

Commit 29d2b8b

Browse files
Leo Altaxic
Leo Alt
authored andcommitted
Fix smtchecker callback tests and add Eldarica
1 parent 6f8b14c commit 29d2b8b

File tree

4 files changed

+47
-21
lines changed

4 files changed

+47
-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-
const result = solver(query);
31+
const result = solverFunction(query, solver);
3232
return { contents: result };
3333
} catch (err) {
3434
return { error: err };

smtsolver.js

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

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

89
const 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-
const solvers = potentialSolvers.filter(solver => commandExistsSync(solver.name));
1926

20-
function solve (query) {
21-
if (solvers.length === 0) {
22-
throw new Error('No SMT solver available. Assertion checking will not be performed.');
27+
const solvers = potentialSolvers.filter(solver => commandExistsSync(solver.command));
28+
29+
function solve (query, solver) {
30+
if (solver === undefined) {
31+
if (solvers.length === 0) {
32+
throw new Error('No SMT solver available. Assertion checking will not be performed.');
33+
} else {
34+
solver = solvers[0];
35+
}
2336
}
2437

2538
const tmpFile = tmp.fileSync({ postfix: '.smt2' });
2639
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).
3240
let solverOutput;
3341
try {
3442
solverOutput = execSync(
35-
solvers[0].name + ' ' + solvers[0].params + ' ' + tmpFile.name, {
43+
solver.command + ' ' + solver.params + ' ' + tmpFile.name, {
3644
stdio: 'pipe'
3745
}
3846
).toString();
@@ -44,7 +52,9 @@ function solve (query) {
4452
if (
4553
!solverOutput.startsWith('sat') &&
4654
!solverOutput.startsWith('unsat') &&
47-
!solverOutput.startsWith('unknown')
55+
!solverOutput.startsWith('unknown') &&
56+
!solverOutput.startsWith('(error') &&
57+
!solverOutput.startsWith('error')
4858
) {
4959
throw new Error('Failed to solve SMT query. ' + e.toString());
5060
}
@@ -56,5 +66,5 @@ function solve (query) {
5666

5767
module.exports = {
5868
smtSolver: solve,
59-
availableSolvers: solvers.length
69+
availableSolvers: solvers
6070
};

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

+15-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
const 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
const re = new RegExp(option + '(\\w+)');
175176
const m = source.match(re);
@@ -211,15 +212,22 @@ tape('SMTCheckerCallback', function (t) {
211212
// `pragma experimental SMTChecker;` was deprecated in 0.8.4
212213
if (semver.gt(solc.semver(), '0.8.3')) {
213214
const engine = test.engine !== undefined ? test.engine : 'all';
214-
settings = { modelChecker: { engine: engine } };
215+
settings = {
216+
modelChecker: {
217+
engine: engine,
218+
solvers: [
219+
'smtlib2'
220+
]
221+
}
222+
};
215223
}
216224
const output = JSON.parse(solc.compile(
217225
JSON.stringify({
218226
language: 'Solidity',
219227
sources: test.solidity,
220228
settings: settings
221229
}),
222-
{ smtSolver: smtchecker.smtCallback(smtsolver.smtSolver) }
230+
{ smtSolver: smtchecker.smtCallback(smtsolver.smtSolver, z3HornSolvers[0]) }
223231
));
224232
st.ok(output);
225233

0 commit comments

Comments
 (0)