Skip to content

Commit 3e164c8

Browse files
authored
Merge pull request #762 from viperproject/lbrugger_smoke
Smoke Detection Plugin
2 parents 07d7c4f + 3f0198a commit 3e164c8

20 files changed

Lines changed: 464 additions & 24 deletions

src/main/scala/viper/silver/frontend/SilFrontEndConfig.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ abstract class SilFrontendConfig(args: Seq[String], private var projectName: Str
8282
hidden = true
8383
)
8484

85+
val enableSmokeDetection = opt[Boolean]("enableSmokeDetection",
86+
descr = "Enable smoke detection (if enabled, refute false statements are inserted in the code in order to detect unsound specifications).",
87+
default = Some(false),
88+
noshort = true,
89+
hidden = false
90+
)
91+
8592
val disableDefaultPlugins = opt[Boolean]("disableDefaultPlugins",
8693
descr = "Deactivate all default plugins.",
8794
default = Some(false),

src/main/scala/viper/silver/frontend/SilFrontend.scala

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,21 @@ trait SilFrontend extends DefaultFrontend {
3131
*/
3232
object ApplicationExitReason extends Enumeration {
3333
type PreVerificationFailureReasons = Value
34-
val UNKNOWN_EXIT_REASON = Value(-2)
35-
val NOTHING_TO_BE_DONE = Value(-1)
36-
val VERIFICATION_SUCCEEDED = Value( 0) // POSIX standard
37-
val VERIFICATION_FAILED = Value( 1)
38-
val COMMAND_LINE_ARGS_PARSE_FAILED = Value( 2)
39-
val ISSUE_WITH_PLUGINS = Value( 3)
40-
val SYSTEM_DEPENDENCY_UNSATISFIED = Value( 4)
34+
val UNKNOWN_EXIT_REASON = Value(-2)
35+
val NOTHING_TO_BE_DONE = Value(-1)
36+
val VERIFICATION_SUCCEEDED = Value(0) // POSIX standard
37+
val VERIFICATION_FAILED = Value(1)
38+
val COMMAND_LINE_ARGS_PARSE_FAILED = Value(2)
39+
val ISSUE_WITH_PLUGINS = Value(3)
40+
val SYSTEM_DEPENDENCY_UNSATISFIED = Value(4)
4141
}
4242

4343
protected var _appExitReason: ApplicationExitReason.Value = ApplicationExitReason.UNKNOWN_EXIT_REASON
44+
4445
def appExitCode: Int = _appExitReason.id
4546

4647
protected def specifyAppExitCode(): Unit = {
47-
if ( _state >= DefaultStates.Verification ) {
48+
if (_state >= DefaultStates.Verification) {
4849
_appExitReason = result match {
4950
case Success => ApplicationExitReason.VERIFICATION_SUCCEEDED
5051
case Failure(_) => ApplicationExitReason.VERIFICATION_FAILED
@@ -55,7 +56,10 @@ trait SilFrontend extends DefaultFrontend {
5556
def resetPlugins(): Unit = {
5657
val pluginsArg: Option[String] = if (_config != null) {
5758
// concat defined plugins and default plugins
58-
val list = _config.plugin.toOption ++ (if (_config.disableDefaultPlugins()) Seq() else defaultPlugins)
59+
val list = (if (_config.enableSmokeDetection()) Set(smokeDetectionPlugin, refutePlugin) else Set()) ++
60+
(if (_config.disableDefaultPlugins()) Set() else defaultPlugins) ++
61+
_config.plugin.toOption.toSet
62+
5963
if (list.isEmpty) {
6064
None
6165
} else {
@@ -75,31 +79,37 @@ trait SilFrontend extends DefaultFrontend {
7579
def createVerifier(fullCmd: String): Verifier
7680

7781
/** Configures the verifier by passing it the command line arguments ''args''.
78-
* Returns the verifier's effective configuration.
79-
*/
82+
* Returns the verifier's effective configuration.
83+
*/
8084
def configureVerifier(args: Seq[String]): SilFrontendConfig
8185

8286
/** The Viper verifier to be used for verification (after it has been initialized). */
8387
def verifier: Verifier = _ver
88+
8489
protected var _ver: Verifier = _
8590

8691
override protected type ParsingResult = PProgram
8792
override protected type SemanticAnalysisResult = PProgram
8893

8994
/** The current configuration. */
9095
protected var _config: SilFrontendConfig = _
96+
9197
def config: SilFrontendConfig = _config
9298

99+
private val refutePlugin: String = "viper.silver.plugin.standard.refute.RefutePlugin"
100+
private val smokeDetectionPlugin: String = "viper.silver.plugin.standard.smoke.SmokeDetectionPlugin"
101+
93102
/**
94103
* Default plugins are always activated and are run as last plugins.
95104
* All default plugins can be excluded from the plugins by providing the --disableDefaultPlugins flag
96105
*/
97106
private val defaultPlugins: Seq[String] = Seq(
98107
"viper.silver.plugin.standard.adt.AdtPlugin",
99108
"viper.silver.plugin.standard.termination.TerminationPlugin",
100-
"viper.silver.plugin.standard.refute.RefutePlugin",
101-
"viper.silver.plugin.standard.predicateinstance.PredicateInstancePlugin"
109+
"viper.silver.plugin.standard.predicateinstance.PredicateInstancePlugin",
110+
refutePlugin
102111
)
112+
103113
/** For testing of plugin import feature */
104114
def defaultPluginCount: Int = defaultPlugins.size
105115

@@ -116,6 +126,7 @@ trait SilFrontend extends DefaultFrontend {
116126
def plugins: SilverPluginManager = _plugins
117127

118128
protected var _startTime: Long = _
129+
119130
def startTime: Time = _startTime
120131

121132
def getTime: Long = System.currentTimeMillis() - _startTime
@@ -124,13 +135,13 @@ trait SilFrontend extends DefaultFrontend {
124135
Consistency.resetMessages()
125136
}
126137

127-
def setVerifier(verifier:Verifier): Unit = {
138+
def setVerifier(verifier: Verifier): Unit = {
128139
_ver = verifier
129140
}
130141

131142
def prepare(args: Seq[String]): Boolean = {
132143

133-
reporter report CopyrightReport(_ver.signature)//${_ver.copyright}") // we agreed on 11/03/19 to drop the copyright
144+
reporter report CopyrightReport(_ver.signature) //${_ver.copyright}") // we agreed on 11/03/19 to drop the copyright
134145

135146
/* Parse command line arguments and populate _config */
136147
parseCommandLine(args)
@@ -189,16 +200,16 @@ trait SilFrontend extends DefaultFrontend {
189200
finish()
190201
}
191202
catch {
192-
case MissingDependencyException(msg) =>
193-
println("Missing dependency exception: " + msg)
194-
reporter report MissingDependencyReport(msg)
203+
case MissingDependencyException(msg) =>
204+
println("Missing dependency exception: " + msg)
205+
reporter report MissingDependencyReport(msg)
195206
}
196207
}
197208

198209
override def reset(input: Path): Unit = {
199210
super.reset(input)
200211

201-
if(_config != null) {
212+
if (_config != null) {
202213
resetPlugins()
203214
}
204215
}
@@ -224,7 +235,7 @@ trait SilFrontend extends DefaultFrontend {
224235
}
225236

226237
override def verification(): Unit = {
227-
def filter(input: Program): Result[Program] = {
238+
def filter(input: Program): Result[Program] = {
228239
plugins.beforeMethodFilter(input) match {
229240
case Some(inputPlugin) =>
230241
// Filter methods according to command-line arguments.
@@ -277,7 +288,10 @@ trait SilFrontend extends DefaultFrontend {
277288
val result = fp.parse(inputPlugin, file, Some(plugins))
278289
if (result.errors.forall(p => p.isInstanceOf[ParseWarning])) {
279290
reporter report WarningsDuringParsing(result.errors)
280-
Succ({result.initProperties(); result})
291+
Succ({
292+
result.initProperties();
293+
result
294+
})
281295
}
282296
else Fail(result.errors)
283297
case None => Fail(plugins.errors)
@@ -326,7 +340,7 @@ trait SilFrontend extends DefaultFrontend {
326340
}
327341
}
328342

329-
def doConsistencyCheck(input: Program): Result[Program]= {
343+
def doConsistencyCheck(input: Program): Result[Program] = {
330344
var errors = input.checkTransitively
331345
if (backendTypeFormat.isDefined)
332346
errors = errors ++ Consistency.checkBackendTypes(input, backendTypeFormat.get)

src/main/scala/viper/silver/plugin/standard/refute/RefuteErrors.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66

77
package viper.silver.plugin.standard.refute
88

9+
import viper.silver.ast.FalseLit
10+
import viper.silver.plugin.standard.smoke.SmokeDetectionInfo
911
import viper.silver.verifier._
1012

1113
sealed abstract class RefuteError extends ExtensionAbstractVerificationError
1214
sealed abstract class RefuteErrorReason extends ExtensionAbstractErrorReason
1315

1416
case class RefuteFailed(override val offendingNode: Refute, override val reason: ErrorReason, override val cached: Boolean = false) extends RefuteError {
1517
override val id = "refute.failed"
16-
override val text = "Refute holds in all cases or could not be reached (e.g. see Silicon `numberOfErrorsToReport`)."
18+
override val text: String = if (offendingNode.exp.isInstanceOf[FalseLit] && offendingNode.info.getUniqueInfo[SmokeDetectionInfo].isDefined)
19+
"Smoke detection: False could be proven here (which should never hold)." else
20+
"Refute holds in all cases or could not be reached (e.g. see Silicon `numberOfErrorsToReport`)."
1721

1822
override def withNode(offendingNode: errors.ErrorNode = this.offendingNode): RefuteFailed =
1923
RefuteFailed(this.offendingNode, this.reason, this.cached)

src/main/scala/viper/silver/plugin/standard/refute/RefutePlugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class RefutePlugin(@unused reporter: viper.silver.reporter.Reporter,
5656
If(nonDetLocalVarDecl.localVar,
5757
Seqn(Seq(
5858
Assert(exp)(r.pos, RefuteInfo(r)),
59-
Inhale(BoolLit(false)(r.pos))(r.pos)
59+
Inhale(BoolLit(false)(r.pos))(r.pos, Synthesized)
6060
), Seq())(r.pos),
6161
Seqn(Seq(), Seq())(r.pos))(r.pos)
6262
),

0 commit comments

Comments
 (0)