Skip to content

Commit 943aa29

Browse files
authored
Merge pull request #701 from viperproject/meilers_reason_unknown
Add option to report reason-unknown
2 parents 99453d6 + d112a26 commit 943aa29

7 files changed

Lines changed: 63 additions & 9 deletions

File tree

src/main/scala/Config.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
172172
noshort = true
173173
)
174174

175+
val reportReasonUnknown: ScallopOption[Boolean] = opt[Boolean]("reportReasonUnknown",
176+
descr = "For every verification error, include the reason the SMT solver reported unknown.",
177+
default = Some(false),
178+
noshort = true
179+
)
180+
175181
val recursivePredicateUnfoldings: ScallopOption[Int] = opt[Int]("recursivePredicateUnfoldings",
176182
descr = ( "Evaluate n unfolding expressions in the body of predicates that (transitively) unfold "
177183
+ "other instances of themselves (default: 1)"),

src/main/scala/decider/Decider.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,6 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
387387

388388
override def isModelValid(): Boolean = prover.isModelValid()
389389

390-
override def clearModel(): Unit = prover.clearLastModel()
390+
override def clearModel(): Unit = prover.clearLastAssert()
391391
}
392392
}

src/main/scala/decider/ProverStdIO.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ abstract class ProverStdIO(uniqueId: String,
4040
protected var output: PrintWriter = _
4141

4242
var proverPath: Path = _
43+
var lastReasonUnknown : String = _
4344
var lastModel : String = _
4445

4546
def exeEnvironmentalVariable: String
@@ -252,6 +253,7 @@ abstract class ProverStdIO(uniqueId: String,
252253

253254
if (!result) {
254255
retrieveAndSaveModel()
256+
retrieveReasonUnknown()
255257
}
256258

257259
pop()
@@ -285,6 +287,16 @@ abstract class ProverStdIO(uniqueId: String,
285287
}
286288
}
287289

290+
protected def retrieveReasonUnknown(): Unit = {
291+
if (Verifier.config.reportReasonUnknown()) {
292+
writeLine("(get-info :reason-unknown)")
293+
var result = readLine()
294+
if (result.startsWith("(:reason-unknown \""))
295+
result = result.substring(18, result.length - 2)
296+
lastReasonUnknown = result
297+
}
298+
}
299+
288300
override def hasModel(): Boolean = {
289301
lastModel != null
290302
}
@@ -474,5 +486,10 @@ abstract class ProverStdIO(uniqueId: String,
474486

475487
override def getModel(): Model = Model(lastModel)
476488

477-
override def clearLastModel(): Unit = lastModel = null
489+
override def getReasonUnknown(): String = lastReasonUnknown
490+
491+
override def clearLastAssert(): Unit = {
492+
lastReasonUnknown = null
493+
lastModel = null
494+
}
478495
}

src/main/scala/decider/Z3ProverAPI.scala

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ class Z3ProverAPI(uniqueId: String,
8585
protected var ctx: Context = _
8686

8787
var proverPath: Path = _
88+
var lastReasonUnknown : String = _
8889
var lastModel : Model = _
8990

9091
var emittedPreambleString = mutable.Queue[String]()
@@ -246,6 +247,7 @@ class Z3ProverAPI(uniqueId: String,
246247

247248
if (!result) {
248249
retrieveAndSaveModel()
250+
retrieveReasonUnknown()
249251
}
250252

251253
(result, endTime - startTime)
@@ -272,6 +274,12 @@ class Z3ProverAPI(uniqueId: String,
272274
}
273275
}
274276

277+
protected def retrieveReasonUnknown(): Unit = {
278+
if (Verifier.config.reportReasonUnknown()) {
279+
lastReasonUnknown = prover.getReasonUnknown
280+
}
281+
}
282+
275283
protected def assertUsingSoftConstraints(goal: Term, timeout: Option[Int]): (Boolean, Long) = {
276284
endPreamblePhase()
277285
setTimeout(timeout)
@@ -417,7 +425,12 @@ class Z3ProverAPI(uniqueId: String,
417425
lastModel != null
418426
}
419427

420-
override def clearLastModel(): Unit = lastModel = null
428+
override def getReasonUnknown(): String = lastReasonUnknown
429+
430+
override def clearLastAssert(): Unit = {
431+
lastReasonUnknown = null
432+
lastModel = null
433+
}
421434

422435
protected def setTimeout(timeout: Option[Int]): Unit = {
423436
val effectiveTimeout = timeout.getOrElse(Verifier.config.proverTimeout)

src/main/scala/interfaces/Verification.scala

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ case class Failure/*[ST <: Store[ST],
100100
override lazy val toString: String = message.readableMessage
101101
}
102102

103-
case class SiliconFailureContext(branchConditions: Seq[ast.Exp], counterExample: Option[Counterexample]) extends FailureContext {
103+
case class SiliconFailureContext(branchConditions: Seq[ast.Exp],
104+
counterExample: Option[Counterexample],
105+
reasonUnknown: Option[String]) extends FailureContext {
104106
lazy val branchConditionString: String = {
105107
if(branchConditions.nonEmpty) {
106108
val branchConditionsString =
@@ -118,7 +120,15 @@ case class SiliconFailureContext(branchConditions: Seq[ast.Exp], counterExample:
118120
counterExample.fold("")(ce => s"\n\t\tcounterexample:\n$ce")
119121
}
120122

121-
override lazy val toString: String = branchConditionString + counterExampleString
123+
lazy val reasonUnknownString: String = {
124+
if (reasonUnknown.isDefined) {
125+
s"\nPotential prover incompleteness: ${reasonUnknown.get}"
126+
} else {
127+
""
128+
}
129+
}
130+
131+
override lazy val toString: String = branchConditionString + counterExampleString + reasonUnknownString
122132
}
123133

124134
trait SiliconCounterexample extends Counterexample {

src/main/scala/interfaces/decider/Prover.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ trait Prover extends ProverLike with StatefulComponent {
3737
def hasModel(): Boolean
3838
def isModelValid(): Boolean
3939
def getModel(): Model
40-
def clearLastModel(): Unit
41-
40+
def getReasonUnknown(): String
41+
def clearLastAssert(): Unit
4242
def name: String
4343
def minVersion: Version
4444
def maxVersion: Option[Version]

src/main/scala/rules/SymbolicExecutionRules.scala

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ trait SymbolicExecutionRules {
2323
wrapped
2424
case _ => ve
2525
}
26-
val counterexample: Option[Counterexample] = if (v != null && Verifier.config.counterexample.toOption.isDefined) {
26+
if (v != null && (Verifier.config.reportReasonUnknown() || Verifier.config.counterexample.toOption.isDefined)) {
2727
if (generateNewModel || !v.decider.hasModel()) {
2828
v.decider.generateModel()
2929
}
30+
}
31+
val counterexample: Option[Counterexample] = if (v != null && Verifier.config.counterexample.toOption.isDefined) {
3032
if (v.decider.isModelValid()) {
3133
val nativeModel = v.decider.getModel()
3234
val ce_type = Verifier.config.counterexample()
@@ -47,6 +49,12 @@ trait SymbolicExecutionRules {
4749
} else None
4850
} else None
4951

52+
val reasonUnknown = if (v != null && Verifier.config.reportReasonUnknown()) {
53+
Some(v.decider.prover.getReasonUnknown())
54+
} else {
55+
None
56+
}
57+
5058
val branchconditions = if (Verifier.config.enableBranchconditionReporting()) {
5159
v.decider.pcs.branchConditionExps.flatten
5260
.filterNot(e => e.isInstanceOf[viper.silver.ast.TrueLit]) /* remove "true" bcs introduced by viper.silicon.utils.ast.BigAnd */
@@ -56,7 +64,7 @@ trait SymbolicExecutionRules {
5664
case _ => (-1, -1)
5765
})
5866
} else Seq()
59-
res.failureContexts = Seq(SiliconFailureContext(branchconditions, counterexample))
67+
res.failureContexts = Seq(SiliconFailureContext(branchconditions, counterexample, reasonUnknown))
6068
Failure(res, v.reportFurtherErrors())
6169

6270
}

0 commit comments

Comments
 (0)