Skip to content

Commit

Permalink
Add READ_DDR AccesType for collectVarsWithAccessType for datarace checks
Browse files Browse the repository at this point in the history
  • Loading branch information
sisakb committed Dec 4, 2023
1 parent ec30274 commit 15250f2
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,25 @@ public static void collectVarsWithoutAddrOf(final Expr<?> expr, final Collection
expr.getOps().forEach(op -> collectVarsWithoutAddrOf(op, collectTo));
}

/**
* Collect variables in address-of expressions of an expression into a given collection.
*
* @param expr Expression
* @param collectTo Collection where the variables should be put
*/
public static void collectVarsInAddrOf(final Expr<?> expr, final Collection<VarDecl<?>> collectTo) {
if (expr instanceof AddrOfExpr<?>) {
final AddrOfExpr<?> addrOfExpr = (AddrOfExpr<?>) expr;
final Decl<?> decl = ((RefExpr<?>) addrOfExpr.getOp()).getDecl();
if (decl instanceof VarDecl) {
final VarDecl<?> varDecl = (VarDecl<?>) decl;
collectTo.add(varDecl);
}
return;
}
expr.getOps().forEach(op -> collectVarsWithoutAddrOf(op, collectTo));
}

/**
* Collect variables from expressions into a given collection.
*
Expand Down Expand Up @@ -190,14 +209,26 @@ public static Set<VarDecl<?>> getVars(final Expr<?> expr) {
* Get variables of an expression, excluding those only appearing in address-of expressions.
*
* @param expr Expression
* @return Set of variables appearing in the expression
* @return Set of variables appearing in the expression, excluding those only appearing in address-of expressions
*/
public static Set<VarDecl<?>> getVarsWithoutAddrOf(final Expr<?> expr) {
final Set<VarDecl<?>> vars = Containers.createSet();
collectVarsWithoutAddrOf(expr, vars);
return vars;
}

/**
* Get variables of an expression appearing in address-of expressions.
*
* @param expr Expression
* @return Set of variables appearing in address-of expressions in the expression
*/
public static Set<VarDecl<?>> getVarsInAddrOf(final Expr<?> expr) {
final Set<VarDecl<?>> vars = Containers.createSet();
collectVarsInAddrOf(expr, vars);
return vars;
}

/**
* Get variables of expressions.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ public static Set<VarDecl<?>> getVarsWithoutAddrOf(final Stmt stmt) {
return vars;
}

/**
* Get variables appearing only in address-of expressions in a statement.
*
* @param stmt Statement
* @return Variables
*/
public static Set<VarDecl<?>> getVarsInAddrOf(final Stmt stmt) {
final Set<VarDecl<?>> vars = Containers.createSet();
stmt.accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
return vars;
}

/**
* Get variables appearing in statements
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright 2023 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.core.utils;

import hu.bme.mit.theta.core.decl.VarDecl;
import hu.bme.mit.theta.core.stmt.*;
import hu.bme.mit.theta.core.type.Type;

import java.util.Collection;

final class VarCollectorStmtVisitorInAddrOf implements StmtVisitor<Collection<VarDecl<?>>, Void> {

private static final class LazyHolder {

private final static VarCollectorStmtVisitorInAddrOf INSTANCE = new VarCollectorStmtVisitorInAddrOf();
}

private VarCollectorStmtVisitorInAddrOf() {
}

static VarCollectorStmtVisitorInAddrOf getInstance() {
return LazyHolder.INSTANCE;
}

@Override
public Void visit(final SkipStmt stmt, final Collection<VarDecl<?>> vars) {
return null;
}

@Override
public Void visit(final AssumeStmt stmt, final Collection<VarDecl<?>> vars) {
ExprUtils.collectVarsInAddrOf(stmt.getCond(), vars);
return null;
}

@Override
public <DeclType extends Type> Void visit(final AssignStmt<DeclType> stmt,
final Collection<VarDecl<?>> vars) {
ExprUtils.collectVarsInAddrOf(stmt.getExpr(), vars);
return null;
}

@Override
public <DeclType extends Type> Void visit(final HavocStmt<DeclType> stmt,
final Collection<VarDecl<?>> vars) {
return null;
}

@Override
public Void visit(SequenceStmt stmt, Collection<VarDecl<?>> vars) {
for (Stmt subStmt : stmt.getStmts()) {
subStmt.accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
}
return null;
}

@Override
public Void visit(NonDetStmt stmt, Collection<VarDecl<?>> vars) {
for (Stmt subStmt : stmt.getStmts()) {
subStmt.accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
}
return null;
}

@Override
public Void visit(OrtStmt stmt, Collection<VarDecl<?>> vars) {
for (Stmt subStmt : stmt.getStmts()) {
subStmt.accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
}
return null;
}

@Override
public Void visit(LoopStmt stmt, Collection<VarDecl<?>> vars) {
ExprUtils.collectVarsInAddrOf(stmt.getFrom(), vars);
ExprUtils.collectVarsInAddrOf(stmt.getTo(), vars);
return stmt.getStmt().accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
}

public Void visit(IfStmt stmt, Collection<VarDecl<?>> vars) {
ExprUtils.collectVarsInAddrOf(stmt.getCond(), vars);
stmt.getThen().accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
stmt.getElze().accept(VarCollectorStmtVisitorInAddrOf.getInstance(), vars);
return null;
}

@Override
public Void visit(DerefWriteStmt stmt, Collection<VarDecl<?>> vars) {
ExprUtils.collectVarsInAddrOf(stmt.getDeRef(), vars);
ExprUtils.collectVarsInAddrOf(stmt.getExpr(), vars);
return null;
}

@Override
public Void visit(PointerDereffedStmt stmt, Collection<VarDecl<?>> param) {
return null;
}

}
36 changes: 25 additions & 11 deletions subprojects/xcfa/xcfa/src/main/java/hu/bme/mit/theta/xcfa/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,19 @@ fun XcfaLabel.collectVars(): Iterable<VarDecl<*>> = when (this) {

// Complex var access requests

typealias AccessType = Pair<Boolean, Boolean>
typealias AccessType = Triple<Boolean, Boolean, Boolean>
private typealias VarAccessMap = Map<VarDecl<*>, AccessType>

val AccessType?.isRead get() = this?.first == true
val AccessType?.isWritten get() = this?.second == true
val AccessType?.isAddressRead get() = this?.third == true
fun AccessType?.merge(other: AccessType?) =
Pair(this?.first == true || other?.first == true, this?.second == true || other?.second == true)
Triple(this?.first == true || other?.first == true, this?.second == true || other?.second == true,
this?.third == true || other?.third == true)

val WRITE: AccessType get() = Pair(false, true)
val READ: AccessType get() = Pair(true, false)
val WRITE: AccessType get() = Triple(false, true, false)
val READ: AccessType get() = Triple(true, false, false)
val READ_ADDRESS: AccessType get() = Triple(false, false, true)

private fun List<VarAccessMap>.mergeAndCollect(): VarAccessMap = this.fold(mapOf()) { acc, next ->
(acc.keys + next.keys).associateWith { acc[it].merge(next[it]) }
Expand Down Expand Up @@ -154,18 +157,29 @@ fun XcfaLabel.collectVarsWithAccessType(): VarAccessMap = when (this) {
is StmtLabel -> {
when (stmt) {
is HavocStmt<*> -> mapOf(stmt.varDecl to WRITE)
is AssignStmt<*> -> ExprUtils.getVarsWithoutAddrOf(stmt.expr).associateWith { READ } + mapOf(
stmt.varDecl to WRITE)
is AssignStmt<*> -> {
val varsWithoutAddrOf = ExprUtils.getVarsWithoutAddrOf(stmt.expr)
val varsInAddrOf = ExprUtils.getVarsInAddrOf(stmt.expr)
varsWithoutAddrOf.associateWith { READ } + varsInAddrOf.associateWith { READ_ADDRESS } + mapOf(
stmt.varDecl to WRITE)
}

else -> StmtUtils.getVarsWithoutAddrOf(stmt).associateWith { READ }
else -> StmtUtils.getVarsWithoutAddrOf(stmt).associateWith { READ } + StmtUtils.getVarsInAddrOf(stmt)
.associateWith { READ_ADDRESS }
}
}

is NondetLabel -> labels.map { it.collectVarsWithAccessType() }.mergeAndCollect()
is SequenceLabel -> labels.map { it.collectVarsWithAccessType() }.mergeAndCollect()
is InvokeLabel -> params.map { ExprUtils.getVarsWithoutAddrOf(it) }.flatten().associateWith { READ }
is StartLabel -> params.map { ExprUtils.getVarsWithoutAddrOf(it) }.flatten().associateWith { READ } + mapOf(
pidVar to READ)
is InvokeLabel -> params.map {
ExprUtils.getVarsWithoutAddrOf(it).associateWith { READ } + ExprUtils.getVarsInAddrOf(it)
.associateWith { READ_ADDRESS }
}.mergeAndCollect()

is StartLabel -> params.map {
ExprUtils.getVarsWithoutAddrOf(it).associateWith { READ } + ExprUtils.getVarsInAddrOf(it)
.associateWith { READ_ADDRESS }
}.mergeAndCollect() + mapOf(pidVar to WRITE)

is JoinLabel -> mapOf(pidVar to READ)
is ReadLabel -> mapOf(global to READ, local to READ)
Expand All @@ -177,7 +191,7 @@ fun XcfaLabel.collectVarsWithAccessType(): VarAccessMap = when (this) {
* Returns the global variables accessed by the label (the variables present in the given argument).
*/
private fun XcfaLabel.collectGlobalVars(globalVars: Set<VarDecl<*>>): VarAccessMap =
collectVarsWithAccessType().filter { labelVar -> globalVars.any { it == labelVar.key } }
collectVarsWithAccessType().filter { labelVar -> globalVars.any { it == labelVar.key } && (labelVar.value.isRead || labelVar.value.isWritten) }

/**
* Returns the global variables (potentially indirectly) accessed by the edge.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import hu.bme.mit.theta.core.utils.TypeUtils.cast
import hu.bme.mit.theta.frontend.ParseContext
import hu.bme.mit.theta.frontend.transformation.model.types.complex.CComplexType
import hu.bme.mit.theta.xcfa.collectVarsWithAccessType
import hu.bme.mit.theta.xcfa.isAddressRead
import hu.bme.mit.theta.xcfa.isRead
import hu.bme.mit.theta.xcfa.model.*

Expand All @@ -48,9 +49,7 @@ class SimplifyExprsPass(val parseContext: ParseContext) : ProcedurePass {

override fun run(builder: XcfaProcedureBuilder): XcfaProcedureBuilder {
checkNotNull(builder.metaData["deterministic"])
// TODO: This would remove variable writes that are only used through pointers
// e.g. in /sv-benchmarks/c/ldv-regression/test09.c, the write to b is removed from the xcfa
// removeUnusedGlobalVarWrites(builder)
removeUnusedGlobalVarWrites(builder)
// TODO: this does not work if the program contains deRefWrites
// e.g. x = 1; y = &x; *y = 2;
// Maybe we should run a static analysis on the xcfa first, to find out which variables are constant
Expand Down Expand Up @@ -96,7 +95,7 @@ class SimplifyExprsPass(val parseContext: ParseContext) : ProcedurePass {
val xcfaBuilder = builder.parent
xcfaBuilder.getProcedures().flatMap { it.getEdges() }.forEach {
it.label.collectVarsWithAccessType().forEach { (varDecl, access) ->
if (access.isRead) usedVars.add(varDecl)
if (access.isRead || access.isAddressRead) usedVars.add(varDecl)
}
}
val unusedVars = xcfaBuilder.getVars().map { it.wrappedVar } union builder.getVars() subtract
Expand Down

0 comments on commit 15250f2

Please sign in to comment.