Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
0b46707
add tests
tschoesi May 2, 2021
9baed86
support reporting one error per path
tschoesi May 2, 2021
a19df8b
add comment about execution of argument
tschoesi May 18, 2021
5e33a7e
Merge branch 'master' into feature/recover_from_failed_pure
May 20, 2021
4834a4a
support recovering from pure assertions
Jun 9, 2021
e24f441
add tests for failing pure assertions
Jun 9, 2021
844b0bf
add support for reporting the branch conditions of failed assertions
tschoesi Jun 20, 2021
1457758
add tests
tschoesi May 2, 2021
1c5bebc
support reporting one error per path
tschoesi May 2, 2021
38fcd9b
add comment about execution of argument
tschoesi May 18, 2021
60e1fcb
support recovering from pure assertions
Jun 9, 2021
959252c
add tests for failing pure assertions
Jun 9, 2021
cc13cca
add support for reporting the branch conditions of failed assertions
tschoesi Jun 20, 2021
72a6788
add tests
tschoesi May 2, 2021
fdf24ec
support reporting one error per path
tschoesi May 2, 2021
07fbc23
add comment about execution of argument
tschoesi May 18, 2021
26d54a4
support recovering from pure assertions
Jun 9, 2021
1f321e0
add tests for failing pure assertions
Jun 9, 2021
d4612e9
Merge branch 'feature/report_branch_conditions' of github.com:tschoes…
tschoesi Jun 20, 2021
bdc4abf
add tests
tschoesi May 2, 2021
674f421
support reporting one error per path
tschoesi May 2, 2021
b6ba826
add comment about execution of argument
tschoesi May 18, 2021
7454826
Merge branch 'feature/one_error_per_branch' of github.com:tschoesi/si…
tschoesi Jun 20, 2021
3fe643e
fix empty reduce error
tschoesi Jun 20, 2021
2ac7a42
Merge branch 'feature/recover_from_failed_pure' of github.com:tschoes…
tschoesi Jun 20, 2021
1eb64c0
cosmetic change
tschoesi Jun 21, 2021
ae5b9b2
Merge branch 'feature/one_error_per_branch' into feature/report_branc…
tschoesi Jun 22, 2021
d9673ab
cosmetic change
Jun 25, 2021
1f89df2
change branchcondition stack to option
Jun 25, 2021
0ea7bf1
change line endings to LF
Jun 25, 2021
ee21db9
add space after comma
Jun 25, 2021
b7495e7
remove unused imports
Jun 25, 2021
928ad58
merge master bc. line endings
Jun 27, 2021
84a4e60
add some tests with failing pure assertions
Jun 29, 2021
57ec8a0
support recovering from pure assertions
Jun 9, 2021
067a58a
add tests for failing pure assertions
Jun 9, 2021
ed3ef13
add some tests with failing pure assertions
Jun 29, 2021
5aed94b
Merge remote-tracking branch 'origin/feature/recover_from_failed_pure…
Jun 29, 2021
afc837b
add support for reporting the branch conditions of failed assertions
tschoesi Jun 20, 2021
8b06720
add support for reporting the branch conditions of failed assertions
tschoesi Jun 20, 2021
ce3354d
fix empty reduce error
tschoesi Jun 20, 2021
ed571a8
cosmetic change
tschoesi Jun 21, 2021
f4fc4dd
cosmetic change
Jun 25, 2021
1716043
change branchcondition stack to option
Jun 25, 2021
7d492f1
add space after comma
Jun 25, 2021
5c6dd49
remove unused imports
Jun 25, 2021
cc5226f
Merge remote-tracking branch 'origin/feature/report_branch_conditions…
Jun 29, 2021
39d3ba3
change reporting of branchconditions
Jun 29, 2021
23b71ef
set branchConditionExp for quantified
tschoesi Jun 30, 2021
0a30ac5
add space after comma
tschoesi Jun 30, 2021
62a8eb1
add FailureContext
Jul 2, 2021
a90f9df
add FailureContext
Jul 2, 2021
49f4086
change toString to mkString
Jul 2, 2021
ff645d3
add some tests
tschoesi Jul 4, 2021
a5898f2
add FailureContext to Silver
tschoesi Jul 6, 2021
94240c2
Merge branch 'master' into feature/report_branch_conditions_merge_wit…
tschoesi Jul 8, 2021
c7659b1
cosmetic changes
tschoesi Jul 13, 2021
350a041
cosmetic changes
tschoesi Jul 13, 2021
7be73a1
cosmetic changes
tschoesi Jul 13, 2021
7a9123d
add comment, rearrange code
tschoesi Jul 13, 2021
5c63ebc
support turning on or off reporting multiple errors
tschoesi Jul 25, 2021
b13adbd
add config option for specifying how many errors to report
tschoesi Jul 25, 2021
d7fd322
fixes mechanism to report number or errors reported
tschoesi Aug 18, 2021
6394ed1
fix numberOfErrors Config
tschoesi Aug 19, 2021
d8f036e
increment Failure count on error creation
tschoesi Aug 19, 2021
89f5960
remove unneccessary space
tschoesi Aug 19, 2021
3b28b51
clarify config description
tschoesi Aug 19, 2021
d145b83
add atomic integer counter
tschoesi Aug 20, 2021
46b92cc
only explore continuation if more errors allowed (even if first op is…
tschoesi Aug 22, 2021
4f2db5a
fix testfile
tschoesi Aug 26, 2021
91e39b8
factor out long boolean expression
tschoesi Aug 26, 2021
cf4a7c9
fix bug that caused quantifiers.vpr to fail
tschoesi Aug 27, 2021
29a8f4a
count errors per member
tschoesi Aug 28, 2021
d86c8f1
change var in case class to val
tschoesi Aug 31, 2021
5fc54b4
cosmetic changes
tschoesi Aug 31, 2021
992d316
typo
tschoesi Aug 31, 2021
439188f
remove testcases - by default silicon won't verify all branches or re…
tschoesi Sep 4, 2021
2389384
Merge remote-tracking branch 'upstream/master' into final_merge_with_…
tschoesi Sep 4, 2021
eb188d0
disable branchConditionReporting by default
tschoesi Sep 5, 2021
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
11 changes: 11 additions & 0 deletions src/main/scala/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,12 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
noshort = true
)

val numberOfErrorsToReport: ScallopOption[Int] = opt[Int]("numberOfErrorsToReport",
descr = "Number of errors per member before the verifier stops. If this number is set to 0, all errors are reported.",
default = Some(1),
noshort = true
)

val stateConsolidationMode: ScallopOption[StateConsolidationMode] = opt[StateConsolidationMode]("stateConsolidationMode",
descr = s"One of the following modes:\n${StateConsolidationMode.helpText}",
default = Some(StateConsolidationMode.Default),
Expand Down Expand Up @@ -502,6 +508,11 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
default = Some(false),
noshort = true
)
val enableBranchconditionReporting: ScallopOption[Boolean] = opt[Boolean]("enableBranchconditionReorting",
descr = "Report branch conditions (can be useful for assertions that fail on multiple branches)",
default = Some(false),
noshort = true
)

val setAxiomatizationFile: ScallopOption[String] = opt[String]("setAxiomatizationFile",
descr =s"Source file with set axiomatisation. If omitted, built-in one is used.",
Expand Down
29 changes: 21 additions & 8 deletions src/main/scala/Silicon.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.slf4j.LoggerFactory
import viper.silver.ast
import viper.silver.frontend.{DefaultStates, SilFrontend}
import viper.silver.reporter._
import viper.silver.verifier.{DefaultDependency => SilDefaultDependency, Failure => SilFailure, Success => SilSuccess, TimeoutOccurred => SilTimeoutOccurred, VerificationResult => SilVerificationResult, Verifier => SilVerifier}
import viper.silver.verifier.{Counterexample => SilCounterexample, DefaultDependency => SilDefaultDependency, Failure => SilFailure, Success => SilSuccess, TimeoutOccurred => SilTimeoutOccurred, VerificationResult => SilVerificationResult, Verifier => SilVerifier}
import viper.silicon.common.config.Version
import viper.silicon.interfaces.Failure
import viper.silicon.logger.SymbExLogger
Expand All @@ -27,6 +27,8 @@ import viper.silver.cfg.silver.SilverCfg
import viper.silver.logger.ViperStdOutLogger
import viper.silver.plugin.PluginAwareReporter

import scala.util.chaining._

object Silicon {
val name = BuildInfo.projectName

Expand Down Expand Up @@ -247,12 +249,23 @@ class Silicon(val reporter: Reporter, private var debugInfo: Seq[(String, Any)]
/*verifier.bookkeeper.*/elapsedMillis = System.currentTimeMillis() - /*verifier.bookkeeper.*/startTime

val failures =
results.flatMap(r => r :: r.allPrevious)
.collect{ case f: Failure => f } /* Ignore successes */
.sortBy(_.message.pos match { /* Order failures according to source position */
case pos: ast.HasLineColumn => (pos.line, pos.column)
case _ => (-1, -1)
})
results.flatMap(r => r :: r.previous.toList)
.collect{ case f: Failure => f } /* Ignore successes */
.pipe(allResults => {
/* If branchconditions are to be reported we collect the different failure contexts
* of all failures that report the same error (but on different branches, with different CounterExample)
* and put those into one failure */
if (config.enableBranchconditionReporting())
allResults.groupBy(_.message.readableMessage(withId = true, withPosition = true)).map{case (_: String, fs:List[Failure]) =>
fs.head.message.failureContexts = fs.flatMap(_.message.failureContexts)
Failure(fs.head.message)
}.toList
else allResults.distinctBy(f => f.message.readableMessage(withId = true, withPosition = true))
})
.sortBy(_.message.pos match { /* Order failures according to source position */
case pos: ast.HasLineColumn => (pos.line, pos.column)
case _ => (-1, -1)
})

// if (config.showStatistics.isDefined) {
// val proverStats = verifier.decider.statistics()
Expand Down Expand Up @@ -283,7 +296,7 @@ class Silicon(val reporter: Reporter, private var debugInfo: Seq[(String, Any)]
failures
}

private def logFailure(failure: Failure, log: String => Unit): Unit = {
private def logFailure(failure: Failure, log: String => Unit): Unit = { //TODO:J log context?
log("\n" + failure.message.readableMessage(withId = true, withPosition = true))
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/scala/decider/Decider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ trait Decider {

def checkSmoke(): Boolean

def setCurrentBranchCondition(t: Term): Unit
def setCurrentBranchCondition(t: Term, te: Option[ast.Exp] = None): Unit
def setPathConditionMark(): Mark

def assume(t: Term): Unit
Expand Down Expand Up @@ -166,8 +166,8 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
//SymbExLogger.currentLog().closeScope(sepIdentifier)
}

def setCurrentBranchCondition(t: Term): Unit = {
pathConditions.setCurrentBranchCondition(t)
def setCurrentBranchCondition(t: Term, te: Option[ast.Exp] = None): Unit = {
pathConditions.setCurrentBranchCondition(t, te)
assume(InsertionOrderedSet(Seq(t)))
}

Expand Down
24 changes: 21 additions & 3 deletions src/main/scala/decider/PathConditions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import viper.silicon.common.collections.immutable.InsertionOrderedSet
import viper.silicon.Stack
import viper.silicon.state.terms._
import viper.silicon.utils.Counter

import viper.silver.ast
/*
* Interfaces
*/
Expand All @@ -22,6 +22,7 @@ import viper.silicon.utils.Counter

trait RecordedPathConditions {
def branchConditions: Stack[Term]
def branchConditionExps: Stack[Option[ast.Exp]]
def assumptions: InsertionOrderedSet[Term]
def declarations: InsertionOrderedSet[Decl]

Expand All @@ -39,7 +40,7 @@ trait RecordedPathConditions {
}

trait PathConditionStack extends RecordedPathConditions {
def setCurrentBranchCondition(condition: Term): Unit
def setCurrentBranchCondition(condition: Term, conditionExp: Option[ast.Exp]): Unit
def add(assumption: Term): Unit
def add(declaration: Decl): Unit
def pushScope(): Unit
Expand All @@ -59,11 +60,13 @@ private class PathConditionStackLayer
extends Cloneable {

private var _branchCondition: Option[Term] = None
private var _branchConditionExp: Option[Option[ast.Exp]] = None
private var _globalAssumptions: InsertionOrderedSet[Term] = InsertionOrderedSet.empty
private var _nonGlobalAssumptions: InsertionOrderedSet[Term] = InsertionOrderedSet.empty
private var _declarations: InsertionOrderedSet[Decl] = InsertionOrderedSet.empty

def branchCondition: Option[Term] = _branchCondition
def branchConditionExp: Option[Option[ast.Exp]] = _branchConditionExp
def globalAssumptions: InsertionOrderedSet[Term] = _globalAssumptions
def nonGlobalAssumptions: InsertionOrderedSet[Term] = _nonGlobalAssumptions
def declarations: InsertionOrderedSet[Decl] = _declarations
Expand All @@ -79,6 +82,14 @@ private class PathConditionStackLayer
_branchCondition = Some(condition)
}

def branchConditionExp_=(condition: Option[ast.Exp]): Unit = {
assert(_branchConditionExp.isEmpty,
s"Branch condition is already set (to ${_branchConditionExp.get}), "
+ s"won't override (with $condition).")

_branchConditionExp = Some(condition)
}

def add(assumption: Term): Unit = {
assert(
!assumption.isInstanceOf[And],
Expand Down Expand Up @@ -116,6 +127,9 @@ private trait LayeredPathConditionStackLike {
protected def branchConditions(layers: Stack[PathConditionStackLayer]): Stack[Term] =
layers.flatMap(_.branchCondition)

protected def branchConditionExps(layers: Stack[PathConditionStackLayer]): Stack[Option[ast.Exp]] =
layers.flatMap(_.branchConditionExp)

protected def assumptions(layers: Stack[PathConditionStackLayer]): InsertionOrderedSet[Term] =
InsertionOrderedSet(layers.flatMap(_.assumptions)) // Note: Performance?

Expand Down Expand Up @@ -175,6 +189,7 @@ private class DefaultRecordedPathConditions(from: Stack[PathConditionStackLayer]
with RecordedPathConditions {

val branchConditions: Stack[Term] = branchConditions(from)
val branchConditionExps: Stack[Option[ast.Exp]] = branchConditionExps(from)
val assumptions: InsertionOrderedSet[Term] = assumptions(from)
val declarations: InsertionOrderedSet[Decl] = declarations(from)

Expand Down Expand Up @@ -209,10 +224,11 @@ private[decider] class LayeredPathConditionStack

pushScope() /* Create an initial layer on the stack */

def setCurrentBranchCondition(condition: Term): Unit = {
def setCurrentBranchCondition(condition: Term, conditionExp: Option[ast.Exp]): Unit = {
/* TODO: Split condition into top-level conjuncts as well? */

layers.head.branchCondition = condition
layers.head.branchConditionExp = conditionExp
}

def add(assumption: Term): Unit = {
Expand Down Expand Up @@ -275,6 +291,8 @@ private[decider] class LayeredPathConditionStack

def branchConditions: Stack[Term] = layers.flatMap(_.branchCondition)

override def branchConditionExps: Stack[Option[ast.Exp]] = layers.flatMap(_.branchConditionExp)

def assumptions: InsertionOrderedSet[Term] = allAssumptions

def declarations: InsertionOrderedSet[Decl] =
Expand Down
57 changes: 38 additions & 19 deletions src/main/scala/interfaces/Verification.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ package viper.silicon.interfaces
import viper.silicon.interfaces.state.Chunk
import viper.silicon.reporting.Converter
import viper.silicon.state.{State, Store}
import viper.silver.verifier.{Counterexample, Model, VerificationError}
import viper.silver.verifier.{Counterexample, FailureContext, Model, VerificationError}
import viper.silicon.state.terms.Term
import viper.silicon.verifier.Verifier
import viper.silver.ast

/*
* Results
Expand All @@ -22,25 +24,34 @@ import viper.silicon.state.terms.Term

/* TODO: Make VerificationResult immutable */
sealed abstract class VerificationResult {
var previous: Option[NonFatalResult] = None
var previous: Vector[VerificationResult] = Vector() //Sets had problems with equality
val continueVerification: Boolean = true

def isFatal: Boolean
def &&(other: => VerificationResult): VerificationResult

def allPrevious: List[VerificationResult] =
previous match {
case None => Nil
case Some(vr) => vr :: vr.allPrevious
}

def append(other: NonFatalResult): VerificationResult =
previous match {
case None =>
this.previous = Some(other)
this
case Some(vr) =>
vr.append(other)
}
/* Attention: Parameter 'other' of 'combine' is a function! That is, the following
* statements
* println(other)
* println(other)
* will invoke the function twice, which might not be what you really want!
*/
def combine(other: => VerificationResult): VerificationResult = {
if (this.continueVerification){
val r: VerificationResult = other
/* Result of combining a failure with a non failure should be a failure.
* When combining two failures, the failure with 'continueVerification'
* set to false (if any) should be the 'head' result */
(this, r) match {
case (_: FatalResult, _: FatalResult) | (_: FatalResult, _: NonFatalResult) if r.continueVerification =>
this.previous = (this.previous :+ r) ++ r.previous
this
case _ =>
r.previous = (r.previous :+ this) ++ this.previous
r
}
} else this
}
}

sealed abstract class FatalResult extends VerificationResult {
Expand All @@ -60,7 +71,7 @@ sealed abstract class NonFatalResult extends VerificationResult {
*/
def &&(other: => VerificationResult): VerificationResult = {
val r: VerificationResult = other
r.append(this)
r.previous = (r.previous :+ this) ++ this.previous
r
}
}
Expand All @@ -76,8 +87,8 @@ case class Unreachable() extends NonFatalResult {
case class Failure/*[ST <: Store[ST],
H <: Heap[H],
S <: State[ST, H, S]]*/
(message: VerificationError)
extends FatalResult {
(message: VerificationError, override val continueVerification: Boolean = true)
extends FatalResult {

/* TODO: Mutable state in a case class? DOOOOOOOOOOOOOON'T! */
var load: Option[Seq[Term]] = None
Expand All @@ -89,6 +100,14 @@ case class Failure/*[ST <: Store[ST],
override lazy val toString = message.readableMessage
}

case class SilFailureContext(branchConditions: Seq[ast.Exp], counterExample: Option[Counterexample]) extends FailureContext {
lazy val branchConditionString = if(branchConditions.nonEmpty)
("\n\t\tunder branch conditions:\n" +
branchConditions.map(bc => (bc.toString + " [ " + bc.pos.toString + " ] ")).mkString("\t\t"," ~~> ","") ) else ""
lazy val counterExampleString = if(counterExample.isDefined) "\n\t\tcounterexample:\n" + counterExample.get.toString else ""
override lazy val toString = branchConditionString + counterExampleString
}

trait SiliconCounterexample extends Counterexample {
val internalStore: Store
lazy val store: Map[String, Term] = internalStore.values.map{case (k, v) => k.name -> v}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/reporting/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ package object reporting {
def convertToViperResult(result: VerificationResult): VprVerificationResult = {
result match {
case Success() | Unreachable() => VprSuccess
case Failure(message) => VprFailure(Seq(message))
case Failure(message, _) => VprFailure(Seq(message))
}
}

Expand Down
9 changes: 5 additions & 4 deletions src/main/scala/rpi/inference/teacher/SampleExtractor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,11 @@ trait SampleExtractor extends AbstractTeacher with LazyLogging {
*/
private def extractInformation[T](error: VerificationError): (Counter, ast.LocationAccess, Option[T]) = {
// extract counter example
val counter = error.counterexample match {
case Some(value: Counter) => value
case _ => sys.error("Verification error does not contain a counter example.")
}
val counters = error.failureContexts.map(_.counterExample).map {case Some(counterexample: SiliconRawCounterexample) => counterexample}
// We should only have multiple CEs at the very end of verification when results are merged
if (counters.length != 1)
sys.error(s"Verification error does not contain exactly one counterexample")
val counter = counters.head
// extract offending location
val offending = error.reason match {
case InsufficientPermission(location) => location
Expand Down
10 changes: 7 additions & 3 deletions src/main/scala/rules/Brancher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import viper.silicon.logger.SymbExLogger
import viper.silicon.state.State
import viper.silicon.state.terms.{Not, Term}
import viper.silicon.verifier.Verifier
import viper.silver.ast

trait BranchingRules extends SymbolicExecutionRules {
def branch(s: State,
condition: Term,
conditionExp: Option[ast.Exp],
v: Verifier,
fromShortCircuitingAnd: Boolean = false)
(fTrue: (State, Verifier) => VerificationResult,
Expand All @@ -27,13 +29,15 @@ trait BranchingRules extends SymbolicExecutionRules {
object brancher extends BranchingRules {
def branch(s: State,
condition: Term,
conditionExp: Option[ast.Exp],
v: Verifier,
fromShortCircuitingAnd: Boolean = false)
(fThen: (State, Verifier) => VerificationResult,
fElse: (State, Verifier) => VerificationResult)
: VerificationResult = {

val negatedCondition = Not(condition)
val negatedConditionExp = conditionExp.fold[Option[ast.Exp]](None)(c => Some(ast.Not(c)(pos = conditionExp.get.pos, info = conditionExp.get.info, ast.NoTrafos)))
val parallelizeElseBranch = s.parallelizeBranches && !s.underJoin

/* Skip path feasibility check if one of the following holds:
Expand Down Expand Up @@ -118,7 +122,7 @@ object brancher extends BranchingRules {
}

v1.decider.prover.comment(s"[else-branch: $cnt | $negatedCondition]")
v1.decider.setCurrentBranchCondition(negatedCondition)
v1.decider.setCurrentBranchCondition(negatedCondition, negatedConditionExp)

fElse(v1.stateConsolidator.consolidateIfRetrying(s1, v1), v1)
})
Expand Down Expand Up @@ -151,13 +155,13 @@ object brancher extends BranchingRules {
SymbExLogger.currentLog().markReachable(uidBranchPoint)
executionFlowController.locally(s, v)((s1, v1) => {
v1.decider.prover.comment(s"[then-branch: $cnt | $condition]")
v1.decider.setCurrentBranchCondition(condition)
v1.decider.setCurrentBranchCondition(condition, conditionExp)

fThen(v1.stateConsolidator.consolidateIfRetrying(s1, v1), v1)
})
} else {
Unreachable()
}) && {
}) combine {

/* [BRANCH-PARALLELISATION] */
if (parallelizeElseBranch) {
Expand Down
Loading