Conversation
…uld be at the start of the smt2 file to be parsed set by private helper method `sanitize` in `AbstractFormulaManager`.
…_as_solver_for_smt-comp # Conflicts: # src/org/sosy_lab/java_smt/basicimpl/AbstractFormulaManager.java
…n running from bin/.
…ging, input checks, error reporting, and shutdown. Added `ShutdownHook`
| final boolean hasCheckSat; | ||
| try { | ||
| hasCheckSat = containsCheckSat(input); | ||
| } catch (IllegalArgumentException e) { |
There was a problem hiding this comment.
We should not silently ignore all input that we can't and don't want to handle.
This includes 2 categories:
- malformed/illegal input. For example
(check-sat-garbage)and(check-sat 1)are currently accepted. - unsupported input.
check-sat-assumingis not supported byparseAll, and is silently ignored.
Most of this is a problem that should be tackled by parseAll in my opinion. @daniel-raffler would you be so kind and open a issue to track this problem, and add unit tests for all allowed SMTLIB2 commands, including malformed ones, e.g. with more arguments than allowed, arguments before the command etc. Then improve the state-machine in parseAll to throw for unsupported or malformed input as long as it can change results. Example:
(declare-fun p () Bool)
(assert p)
(check-sat-assuming ((not p)))
Is UNSAT, but we return SAT currently.
@gcarpio21 what must be blocked are all pop and all resetting commands for now, as we do not properly track assertion stacks through parseAll and also ignore resets. Please add a TODO that explains the problem and that we add it later. (exit) should also throw, except for if its the very last command.
There was a problem hiding this comment.
Hello Daniel,
We should not silently ignore all input that we can't and don't want to handle. This includes 2 categories:
* malformed/illegal input. For example `(check-sat-garbage)` and `(check-sat 1)` are currently accepted. * unsupported input. `check-sat-assuming` is not supported by `parseAll`, and is silently ignored.Most of this is a problem that should be tackled by
parseAllin my opinion
I did some work on this a while ago, and there is an open PR here that should at least take case of your first point about illegal inputs
If we want to support commands like check-sat-assuming, pop or exit, I think it would be easiest to write a proper parser with ANTLR. The tokenizer is more of a stop-gap solution that works well enough for parsing simple formulas, but it was never meant to execute entire SMTLIB scripts
There was a problem hiding this comment.
ANTLR may be overkill for what we want.
I opened a issue for this here, lets discuss it there.
There was a problem hiding this comment.
JavaSMTMain.checkScript now rejects (push ...), (pop ...), (reset) and (reset-assertions), any (exit) that is not the last command, anything that looks like (check-sat) but is not exactly (check-sat), and text outside a command, which the tokenizer would otherwise drop. (push ...) is included because the tokenizer's isForbiddenToken covers it and parseAll fails on it anyway.
baierd
left a comment
There was a problem hiding this comment.
Nice job!
We only need to work out some minor points before merging this.
Could you please also add a --help command that explains restrictions and allowed arguments?
| boolean isUnsat; | ||
| try (ProverEnvironment prover = context.newProverEnvironment()) { | ||
| for (BooleanFormula formula : formulas) { | ||
| prover.addConstraint(formula); |
There was a problem hiding this comment.
This is currently incorrect.
Sat checks should be performed for each and every (check-sat) command. We currently perform one giant SAT check, but this violates SMTLIB2.
I propose to only allow ONE (check-sat) (i.e. use parse instead of parseAll) for now. And extend it later on.
There was a problem hiding this comment.
I kept parseAll for now. parse delegates to parseAll and then throws unless the query contains exactly one assertion. The restriction is instead enforced in JavaSMTMain.checkScript before parsing: exactly one (check-sat), no (assert ...) after it.
| return ERROR_EXIT_CODE; | ||
| } catch (InterruptedException e) { | ||
| // Thrown by the solver after a shutdown request, see ShutdownHook. | ||
| String reason = shutdownNotifier.shouldShutdown() ? shutdownNotifier.getReason() : ""; |
There was a problem hiding this comment.
Please do not use shorthand if-then-else. They are hard to read and provide no benefit at all.
String reason = "";
if (shutdownNotifier.shouldShutdown()) {
reason = shutdownNotifier.getReason();
}Is much easier to read.
There was a problem hiding this comment.
I disagree. Having a single point of assignment is typically easier to follow (less mutable state) and allows variables to be final.
There was a problem hiding this comment.
Fair point.
But that is also quite easy.
final String reason;
if (shutdownNotifier.shouldShutdown()) {
reason = shutdownNotifier.getReason();
} else {
reason = "";
}
There was a problem hiding this comment.
Fair point. But that is also quite easy.
final String reason; if (shutdownNotifier.shouldShutdown()) { reason = shutdownNotifier.getReason(); } else { reason = ""; }
I decided to replace the shorthands with this suggestion.
| } | ||
| isUnsat = prover.isUnsat(); | ||
| } | ||
| Output.println(out, isUnsat ? "unsat" : "sat"); |
There was a problem hiding this comment.
While PrintStream does not swallow IOExceptions from Appendables, System.out and System.err record these failures internally, and flushing does not report them. Thus result delivery can fail while the process reports success. Better: after the existing flushes, check both streams with checkError() and change the exit status to ERROR_EXIT_CODE on failure.
Also, redirect the launchers JVM-probe failure messages to stderr using >&2; that branch currently uses plain echo on stdout.
@PhilippWendler why are we using PrintStream in CPAchecker?
There was a problem hiding this comment.
For example because we do not want to stop proceeding through all the code for statistics and output files if there is an I/O error for the statistics output.
There was a problem hiding this comment.
Makes sense. Thanks for the explanation.
The question now is whether we should use PrintStream or not here as well. Do you have a strong opinion on that @PhilippWendler ?
There was a problem hiding this comment.
This depends a lot on the use case. For I/O in most cases it is bad, but for particular situations it can be ok.
| Preconditions.checkNotNull(pArgs); | ||
|
|
||
| Map<String, String> properties = new HashMap<>(); | ||
| Iterator<String> argsIt = Arrays.asList(pArgs).iterator(); |
There was a problem hiding this comment.
Please avoid Arrays.asList() (and most other default toList, asList etc. methods). Take a look at CPAcheckers StyleGuide for why and for alternatives. In this case, just use ImmutableList.of(pArgs).
There was a problem hiding this comment.
CPAchecker's style guide definitively does not forbid Arrays.asList(), and I wouldn't know what "default toList, asList methods" are.
There was a problem hiding this comment.
My bad, i was a little over-eager here.
Collectors.toList() should be avoided.
The code can be improved either way by using Guavas utilities from its Iterators class;
Iterator<String> argsIt = Iterators.forArray(pArgs);
…files. `JavaSMTMainTest` now tests for this.
- converted repeated Strings into final constants. - changes to style to better adhere to the CPAchecker's StyleGuide. - avoided shorthand if-then-else. - expanded `--help` argument. - only one `(check-sat)` is supported per smt2 file. Assertions after it are rejected. Text outside any command is rejected. `push`, `pop`, `reset` are rejected. - redirect the launchers JVM-probe failure messages to stderr. - exit code 1 if the result could not be written to stdout. - an `InvalidPathException` in `CmdLineArguments` and `JavaSMTMain` was previously not handled. - added some tests and a cleanup of `testMainReportsUnknownWhenTerminated()`. Using `assertThrows` instead of `expected`. - added static analysis hints to the package-info.
the |
|
The main purpose of this command-line interface and the Expected answers (task-definition files)BenchExec only judges a result as correct or wrong if the task is given as a task-definition file (YAML) that states an expected verdict for the property file named in the benchmark definition (benchexec.md); plain input files are executed without checking the result (properties.md). Each task-definition file has exactly one set of input files (INDEX.md), so each benchmark needs its own. SMT-LIB stores the expected answer inside each benchmark as
Benchmark definitionThe benchmark definition (XML) uses ResultsOn the Cloud, QF_LIA worked with z3 alone and with all nine solvers (13,306 tasks, 119,754 runs), and the tables from ProposalSince this setup works, I think it would be useful to add the benchmark definition, the property file, and the script to this PR, so that others can benchmark JavaSMT the same way. The YAML files themselves would not be added, as the script generates them from the SMT-LIB release. |
Command-line interface for running JavaSMT
Adds a command-line interface so that JavaSMT can be run like a regular SMT solver on a single SMT-LIB 2 file, e.g., for SMT-COMP or for benchmarking the solvers behind JavaSMT with BenchExec.
JavaSMTMainparses the assertions withFormulaManager.parseAll, checks them in oneProverEnvironment, and prints exactly one ofsat,unsat, orunknownon stdout; diagnostics got to stderr.--solverselects the solver (default SMTInterpol),--logicis forwarded to OpenSMT. The launcherjavasmtin the project root builds the classpath frombin/or the JAR and all solver runtimes, passes-X*arguments to the JVM, and shares its Java version check and platform handling withrunExamples.sh.(check-sat)is rejected.unknownis reported and the solver is closed. Solvers that do not respond get a grace period of 10 s.parseAllruns before theProverEnvironmentis created, because Princess does not register symbols declared after its prover exists.JavaSMTMainTestcovers the argument parsing and the whole interface in-process with SMTInterpol and Princess, including all error cases and shutdown requests before and during solving; one test runsmainin a separate JVM and sends SIGTERM.