Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/main/scala/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
noshort = true
)

val reportReasonUnknown: ScallopOption[Boolean] = opt[Boolean]("reportReasonUnknown",
descr = "For every verification error, include the reason the SMT solver reported unknown.",
default = Some(false),
noshort = true
)

val recursivePredicateUnfoldings: ScallopOption[Int] = opt[Int]("recursivePredicateUnfoldings",
descr = ( "Evaluate n unfolding expressions in the body of predicates that (transitively) unfold "
+ "other instances of themselves (default: 1)"),
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/decider/Decider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,6 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>

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

override def clearModel(): Unit = prover.clearLastModel()
override def clearModel(): Unit = prover.clearLastAssert()
}
}
19 changes: 18 additions & 1 deletion src/main/scala/decider/ProverStdIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ abstract class ProverStdIO(uniqueId: String,
protected var output: PrintWriter = _

var proverPath: Path = _
var lastReasonUnknown : String = _
var lastModel : String = _

def exeEnvironmentalVariable: String
Expand Down Expand Up @@ -252,6 +253,7 @@ abstract class ProverStdIO(uniqueId: String,

if (!result) {
retrieveAndSaveModel()
retrieveReasonUnknown()
}

pop()
Expand Down Expand Up @@ -285,6 +287,16 @@ abstract class ProverStdIO(uniqueId: String,
}
}

protected def retrieveReasonUnknown(): Unit = {
if (Verifier.config.reportReasonUnknown()) {
writeLine("(get-info :reason-unknown)")
var result = readLine()
if (result.startsWith("(:reason-unknown \""))
result = result.substring(18, result.length - 2)
lastReasonUnknown = result
}
}

override def hasModel(): Boolean = {
lastModel != null
}
Expand Down Expand Up @@ -474,5 +486,10 @@ abstract class ProverStdIO(uniqueId: String,

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

override def clearLastModel(): Unit = lastModel = null
override def getReasonUnknown(): String = lastReasonUnknown

override def clearLastAssert(): Unit = {
lastReasonUnknown = null
lastModel = null
}
}
15 changes: 14 additions & 1 deletion src/main/scala/decider/Z3ProverAPI.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class Z3ProverAPI(uniqueId: String,
protected var ctx: Context = _

var proverPath: Path = _
var lastReasonUnknown : String = _
var lastModel : Model = _

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

if (!result) {
retrieveAndSaveModel()
retrieveReasonUnknown()
}

(result, endTime - startTime)
Expand All @@ -272,6 +274,12 @@ class Z3ProverAPI(uniqueId: String,
}
}

protected def retrieveReasonUnknown(): Unit = {
if (Verifier.config.reportReasonUnknown()) {
lastReasonUnknown = prover.getReasonUnknown
}
}

protected def assertUsingSoftConstraints(goal: Term, timeout: Option[Int]): (Boolean, Long) = {
endPreamblePhase()
setTimeout(timeout)
Expand Down Expand Up @@ -417,7 +425,12 @@ class Z3ProverAPI(uniqueId: String,
lastModel != null
}

override def clearLastModel(): Unit = lastModel = null
override def getReasonUnknown(): String = lastReasonUnknown

override def clearLastAssert(): Unit = {
lastReasonUnknown = null
lastModel = null
}

protected def setTimeout(timeout: Option[Int]): Unit = {
val effectiveTimeout = timeout.getOrElse(Verifier.config.proverTimeout)
Expand Down
14 changes: 12 additions & 2 deletions src/main/scala/interfaces/Verification.scala
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ case class Failure/*[ST <: Store[ST],
override lazy val toString: String = message.readableMessage
}

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

override lazy val toString: String = branchConditionString + counterExampleString
lazy val reasonUnknownString: String = {
if (reasonUnknown.isDefined) {
s"\nPotential prover incompleteness: ${reasonUnknown.get}"
} else {
""
}
}

override lazy val toString: String = branchConditionString + counterExampleString + reasonUnknownString
}

trait SiliconCounterexample extends Counterexample {
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/interfaces/decider/Prover.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ trait Prover extends ProverLike with StatefulComponent {
def hasModel(): Boolean
def isModelValid(): Boolean
def getModel(): Model
def clearLastModel(): Unit

def getReasonUnknown(): String
def clearLastAssert(): Unit
def name: String
def minVersion: Version
def maxVersion: Option[Version]
Expand Down
12 changes: 10 additions & 2 deletions src/main/scala/rules/SymbolicExecutionRules.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ trait SymbolicExecutionRules {
wrapped
case _ => ve
}
val counterexample: Option[Counterexample] = if (v != null && Verifier.config.counterexample.toOption.isDefined) {
if (v != null && (Verifier.config.reportReasonUnknown() || Verifier.config.counterexample.toOption.isDefined)) {
if (generateNewModel || !v.decider.hasModel()) {
v.decider.generateModel()
}
}
val counterexample: Option[Counterexample] = if (v != null && Verifier.config.counterexample.toOption.isDefined) {
if (v.decider.isModelValid()) {
val nativeModel = v.decider.getModel()
val ce_type = Verifier.config.counterexample()
Expand All @@ -47,6 +49,12 @@ trait SymbolicExecutionRules {
} else None
} else None

val reasonUnknown = if (v != null && Verifier.config.reportReasonUnknown()) {
Some(v.decider.prover.getReasonUnknown())
} else {
None
}

val branchconditions = if (Verifier.config.enableBranchconditionReporting()) {
v.decider.pcs.branchConditionExps.flatten
.filterNot(e => e.isInstanceOf[viper.silver.ast.TrueLit]) /* remove "true" bcs introduced by viper.silicon.utils.ast.BigAnd */
Expand All @@ -56,7 +64,7 @@ trait SymbolicExecutionRules {
case _ => (-1, -1)
})
} else Seq()
res.failureContexts = Seq(SiliconFailureContext(branchconditions, counterexample))
res.failureContexts = Seq(SiliconFailureContext(branchconditions, counterexample, reasonUnknown))
Failure(res, v.reportFurtherErrors())

}
Expand Down