hu.bme.mit.theta.xcfa.cli.utils.YmlWitnessWriter.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of theta-xcfa-cli Show documentation
Show all versions of theta-xcfa-cli Show documentation
Xcfa Cli subproject in the Theta model checking framework
The newest version!
/*
* Copyright 2024 Budapest University of Technology and Economics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package hu.bme.mit.theta.xcfa.cli.utils
import hu.bme.mit.theta.analysis.Trace
import hu.bme.mit.theta.analysis.algorithm.Proof
import hu.bme.mit.theta.analysis.algorithm.SafetyResult
import hu.bme.mit.theta.analysis.algorithm.arg.ARG
import hu.bme.mit.theta.analysis.algorithm.arg.ArgNode
import hu.bme.mit.theta.analysis.expl.ExplState
import hu.bme.mit.theta.analysis.ptr.PtrState
import hu.bme.mit.theta.c2xcfa.CMetaData
import hu.bme.mit.theta.core.type.booltype.BoolExprs.Or
import hu.bme.mit.theta.core.utils.ExprUtils
import hu.bme.mit.theta.frontend.ParseContext
import hu.bme.mit.theta.frontend.transformation.ArchitectureConfig
import hu.bme.mit.theta.solver.SolverFactory
import hu.bme.mit.theta.xcfa.analysis.ErrorDetection
import hu.bme.mit.theta.xcfa.analysis.XcfaAction
import hu.bme.mit.theta.xcfa.analysis.XcfaState
import hu.bme.mit.theta.xcfa.cli.witnesses.*
import hu.bme.mit.theta.xcfa.model.MetaData
import hu.bme.mit.theta.xcfa.toC
import java.io.File
import java.util.*
class YmlWitnessWriter {
fun writeWitness(
safetyResult: SafetyResult<*, *>,
inputFile: File,
property: ErrorDetection,
architecture: ArchitectureConfig.ArchitectureType?,
cexSolverFactory: SolverFactory,
parseContext: ParseContext,
witnessfile: File,
) {
val metadata =
Metadata(
formatVersion = "2.0",
uuid = UUID.randomUUID().toString(),
creationTime = getIsoDate(),
producer =
Producer(
name = (System.getenv("VERIFIER_NAME") ?: "").ifEmpty { "Theta" },
version = (System.getenv("VERIFIER_VERSION") ?: "").ifEmpty { "no version found" },
),
task =
Task(
inputFiles = listOf(inputFile.name),
inputFileHashes = listOf(createTaskHash(inputFile.path)),
specification = property.name,
dataModel =
architecture?.let {
if (it == ArchitectureConfig.ArchitectureType.ILP32) DataModel.ILP32
else DataModel.LP64
} ?: DataModel.ILP32,
language = Language.C,
),
)
if (safetyResult.isUnsafe && safetyResult.asUnsafe().cex is Trace<*, *>) {
val concrTrace: Trace, XcfaAction> =
XcfaTraceConcretizer.concretize(
safetyResult.asUnsafe().cex as Trace>, XcfaAction>?,
cexSolverFactory,
parseContext,
)
val witnessTrace = traceToWitness(trace = concrTrace, parseContext = parseContext)
val witness =
YamlWitness(
entryType = EntryType.VIOLATION,
metadata = metadata,
content =
(0..(witnessTrace.length())).flatMap {
listOfNotNull(
witnessTrace.states
.get(it)
?.toSegment(witnessTrace.actions.getOrNull(it - 1), inputFile),
witnessTrace.actions.getOrNull(it)?.toSegment(inputFile),
)
},
)
witnessfile.writeText(WitnessYamlConfig.encodeToString(YamlWitness.serializer(), witness))
} else if (safetyResult.isSafe) {
val witness =
YamlWitness(
entryType = EntryType.INVARIANTS,
metadata = metadata,
content = safetyResult.asSafe().proof.toContent(inputFile, parseContext),
)
witnessfile.writeText(WitnessYamlConfig.encodeToString(YamlWitness.serializer(), witness))
}
}
}
private fun getLocation(inputFile: File, metadata: MetaData?): Location? {
val line =
(metadata as? CMetaData)?.lineNumberStart
?: (metadata as? CMetaData)?.lineNumberStop
?: return null
val column = (metadata as? CMetaData)?.colNumberStart ?: (metadata as? CMetaData)?.colNumberStop
return Location(fileName = inputFile.name, line = line, column = column)
}
private fun getLocation(inputFile: File, witnessEdge: WitnessEdge?): Location? {
if (witnessEdge == null) return null
val endLoc =
Location(
fileName = inputFile.name,
line = witnessEdge.endline ?: witnessEdge.startline ?: return null,
column = (witnessEdge.endcol ?: witnessEdge.startcol)?.plus(1),
)
return endLoc
}
private fun WitnessNode.toSegment(witnessEdge: WitnessEdge?, inputFile: File): ContentItem? {
if (violation) {
val loc = xcfaLocations.values.first().first()
val locLoc =
getLocation(inputFile, loc.metadata)
?: getLocation(inputFile, witnessEdge)
?: getLocation(inputFile, witnessEdge?.edge?.metadata)
?: return null
return ContentItem(
Segment(Waypoint(type = WaypointType.TARGET, location = locLoc, action = Action.FOLLOW))
)
} else {
return null
}
}
private fun WitnessEdge.toSegment(inputFile: File): ContentItem? {
val endLoc =
Location(
fileName = inputFile.name,
line = endline ?: startline ?: return null,
column = (endcol ?: startcol)?.plus(1),
)
val startLoc =
Location(
fileName = inputFile.name,
line = startline ?: endline ?: return null,
column = (startcol ?: endcol)?.plus(1),
)
val (loc, constraint, type) =
if (assumption != null) {
Triple(
endLoc,
Constraint(value = assumption, format = Format.C_EXPRESSION),
WaypointType.ASSUMPTION,
)
} else if (control != null) {
Triple(startLoc, Constraint(value = control.toString()), WaypointType.BRANCHING)
} else if (enterLoopHead) {
Triple(startLoc, Constraint(value = "true"), WaypointType.BRANCHING)
} else if (enterFunction != null) {
Triple(startLoc, Constraint(value = enterFunction), WaypointType.FUNCTION_ENTER)
} else if (returnFromFunction != null) {
Triple(endLoc, Constraint(value = returnFromFunction), WaypointType.FUNCTION_RETURN)
} else return null
return ContentItem(
Segment(Waypoint(type = type, constraint = constraint, location = loc, action = Action.FOLLOW))
)
}
private fun Proof.toContent(inputFile: File, parseContext: ParseContext): List {
if (this is ARG<*, *>) {
val locMap =
nodes
.toList()
.mapNotNull {
it as ArgNode, XcfaAction>
val loc = it.state.processes.values.firstOrNull()?.locs?.peek() ?: return@mapNotNull null
val locLoc =
Location(
fileName = inputFile.name,
line =
(loc.metadata as? CMetaData)?.lineNumberStart
?: (loc.metadata as? CMetaData)?.lineNumberStop
?: return@mapNotNull null,
column =
(loc.metadata as? CMetaData)?.colNumberStart
?: (loc.metadata as? CMetaData)?.colNumberStop,
)
locLoc to it.state.sGlobal.toExpr()
}
.groupBy { it.first }
val invs =
locMap
.mapValues { entry -> ExprUtils.simplify(Or(entry.value.map { it.second })) }
.map {
ContentItem(
invariant =
Invariant(
type = InvariantType.LOCATION_INVARIANT,
location = it.key,
value = it.value.toC(parseContext),
format = Format.C_EXPRESSION,
)
)
}
return invs
}
return listOf()
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy