hu.bme.mit.theta.xcfa.cli.witnesses.TraceToWitness.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
/*
* 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.witnesses
import com.google.common.collect.Lists
import hu.bme.mit.theta.analysis.Trace
import hu.bme.mit.theta.analysis.expl.ExplState
import hu.bme.mit.theta.c2xcfa.getCMetaData
import hu.bme.mit.theta.core.model.Valuation
import hu.bme.mit.theta.core.stmt.HavocStmt
import hu.bme.mit.theta.core.type.LitExpr
import hu.bme.mit.theta.core.type.bvtype.BvLitExpr
import hu.bme.mit.theta.core.type.fptype.FpLitExpr
import hu.bme.mit.theta.frontend.ParseContext
import hu.bme.mit.theta.xcfa.analysis.XcfaAction
import hu.bme.mit.theta.xcfa.analysis.XcfaState
import hu.bme.mit.theta.xcfa.model.*
import java.math.BigInteger
enum class Verbosity {
NECESSARY,
SOURCE_EXISTS,
STMT_EXISTS,
EVERYTHING
}
fun traceToWitness(
verbosity: Verbosity = Verbosity.SOURCE_EXISTS,
trace: Trace, XcfaAction>,
parseContext: ParseContext
): Trace {
val newStates = ArrayList()
val newActions = ArrayList()
var lastNode = WitnessNode(id = "N${newStates.size}", entry = true, sink = false,
violation = false)
newStates.add(lastNode)
for (i in 0 until trace.length()) {
val state = trace.states[i]
val nextState = trace.states[i + 1]
val newThreads = nextState.processes.keys - state.processes.keys
val node = WitnessNode(
id = "N${newStates.size}",
entry = false,
sink = false,
violation = state.processes.any { it.value.locs.any(XcfaLocation::error) },
xcfaLocations = state.processes.map { Pair(it.key, it.value.locs) }.toMap(),
cSources = state.processes.map {
Pair(it.key, it.value.locs.map { it.getCMetaData()?.sourceText ?: "" })
}.toMap(),
globalState = state.sGlobal
)
if (node != WitnessNode(id = "N${newStates.size}")) {
newStates.add(node)
val edge = WitnessEdge(sourceId = lastNode.id, targetId = node.id,
threadId = trace.actions[i].pid.toString())
newActions.add(edge)
lastNode = node
}
val action = trace.actions[i]
val flattenedSequence = flattenSequence(action.edge.label)
for (xcfaLabel in flattenedSequence) {
val node = WitnessNode(id = "N${newStates.size}", entry = false, sink = false,
violation = false)
var edge = labelToEdge(lastNode, node, xcfaLabel, action.pid,
nextState.sGlobal.getVal(), parseContext)
if (newThreads.isNotEmpty() && xcfaLabel is StartLabel) {
edge = edge.copy(createThread = newThreads.joinToString(","))
}
if (node != WitnessNode(id = "N${newStates.size}") || shouldInclude(edge, verbosity)) {
newStates.add(node)
newActions.add(edge)
lastNode = node
}
}
}
val lastState = trace.states[trace.length()]
val node = WitnessNode(
id = "N${newStates.size}",
entry = false,
sink = false,
violation = lastState.processes.any { it.value.locs.any(XcfaLocation::error) },
xcfaLocations = lastState.processes.map { Pair(it.key, it.value.locs) }.toMap(),
cSources = lastState.processes.map {
Pair(it.key, it.value.locs.map { it.getCMetaData()?.sourceText ?: "" })
}.toMap(),
globalState = lastState.sGlobal
)
newStates.add(node)
val edge = WitnessEdge(sourceId = lastNode.id, targetId = node.id)
newActions.add(edge)
return Trace.of(newStates, newActions)
}
fun shouldInclude(edge: WitnessEdge, verbosity: Verbosity): Boolean =
when (verbosity) {
Verbosity.NECESSARY -> edge.control != null || edge.assumption != null || edge.createThread != null
Verbosity.SOURCE_EXISTS -> shouldInclude(edge, Verbosity.NECESSARY) || edge.cSource != null
Verbosity.STMT_EXISTS -> shouldInclude(edge, Verbosity.NECESSARY) || edge.stmt != null
Verbosity.EVERYTHING -> true
}
private fun labelToEdge(lastNode: WitnessNode, node: WitnessNode, xcfaLabel: XcfaLabel, pid: Int,
valuation: Valuation, parseContext: ParseContext): WitnessEdge =
WitnessEdge(
sourceId = lastNode.id,
targetId = node.id,
assumption = if (xcfaLabel is StmtLabel && xcfaLabel.stmt is HavocStmt<*>) {
val varDecl = (xcfaLabel.stmt as HavocStmt<*>).varDecl
val eval = valuation.eval(varDecl)
val splitName = varDecl.name.split("::")
val rootName = if (splitName[0].matches(Regex("T[0-9]*"))) splitName.subList(2, splitName.size)
.joinToString("::") else varDecl.name
if (parseContext.metadata.getMetadataValue(rootName, "cName").isPresent && eval.isPresent)
"${parseContext.metadata.getMetadataValue(rootName, "cName").get()} == ${
printLit(eval.get())
}"
else null
} else null,
control = if (xcfaLabel is StmtLabel && xcfaLabel.choiceType != ChoiceType.NONE) {
xcfaLabel.choiceType == ChoiceType.MAIN_PATH
} else null,
startline = xcfaLabel.getCMetaData()?.lineNumberStart,
endline = xcfaLabel.getCMetaData()?.lineNumberStop,
startoffset = xcfaLabel.getCMetaData()?.offsetStart,
endoffset = xcfaLabel.getCMetaData()?.offsetEnd,
threadId = if (pid != null) "$pid" else null,
stmt = if (xcfaLabel is StmtLabel) xcfaLabel.stmt.toString() else null,
cSource = xcfaLabel.getCMetaData()?.sourceText
)
private fun flattenSequence(label: XcfaLabel): List =
when (label) {
is NondetLabel -> error("Cannot handle nondet labels in witnesses")
is SequenceLabel -> label.labels.map { flattenSequence(it) }.flatten()
else -> listOf(label)
}
private fun printLit(litExpr: LitExpr<*>): String? {
return if (litExpr is BvLitExpr) {
val value = litExpr.value
var intValue = BigInteger.ZERO
for (i in value.indices) {
val b = value[i]
if (b) {
intValue = intValue.add(BigInteger.ONE.shiftLeft(value.size - 1 - i))
}
}
"0x" + intValue.toString(16)
} else if (litExpr is FpLitExpr) {
val boolList: MutableList = java.util.ArrayList()
val tmpList: MutableList = java.util.ArrayList()
for (b in litExpr.significand.value) {
tmpList.add(b)
}
boolList.addAll(Lists.reverse(tmpList))
tmpList.clear()
for (b in litExpr.exponent.value) {
tmpList.add(b)
}
boolList.addAll(Lists.reverse(tmpList))
boolList.add(litExpr.hidden)
var aggregate = 0
val hexDigits: MutableList = java.util.ArrayList()
for (i in boolList.indices) {
if (i % 4 == 0 && i > 0) {
if (aggregate < 10) hexDigits.add(
('0'.code + aggregate).toChar()) else hexDigits.add(
('A'.code - 10 + aggregate).toChar())
aggregate = 0
}
if (boolList[i]) aggregate += 1 shl i % 4
}
if (aggregate < 10) hexDigits.add(('0'.code + aggregate).toChar()) else hexDigits.add(
('A'.code - 10 + aggregate).toChar())
val stringBuilder = StringBuilder("0x")
for (character in Lists.reverse(hexDigits)) {
stringBuilder.append(character)
}
stringBuilder.toString()
} else {
litExpr.toString()
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy