Skip to content

Commit

Permalink
Merge pull request #18486 from MathiasVP/indirect-instruction-barriers
Browse files Browse the repository at this point in the history
C++: Add a `BarrierGuard` module for indirect instruction/operand nodes.
  • Loading branch information
MathiasVP authored Jan 14, 2025
2 parents 7196892 + d9d0d93 commit 0ff37f1
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: feature
---
* Add a new predicate `getAnIndirectBarrier` to the parameterized module `InstructionBarrierGuard` in `semmle.code.cpp.dataflow.new.DataFlow` for computing indirect dataflow nodes that are guarded by a given instruction. This predicate is similar to the `getAnIndirectBarrier` predicate on the parameterized module `BarrierGuard`.
30 changes: 30 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2494,6 +2494,36 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
result = TSsaPhiInputNode(phi, input)
)
}

bindingset[value, n]
pragma[inline_late]
private predicate indirectOperandHasValueNumber(ValueNumber value, int indirectionIndex, Node n) {
exists(Operand use |
use = value.getAnInstruction().getAUse() and
n.asIndirectOperand(indirectionIndex) = use
)
}

/**
* Gets an indirect node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
exists(IRGuardCondition g, ValueNumber value, boolean edge |
instructionGuardChecks(g, pragma[only_bind_into](value.getAnInstruction()), edge) and
indirectOperandHasValueNumber(value, indirectionIndex, result) and
controls(g, result, edge)
)
or
exists(
IRGuardCondition g, boolean branch, Ssa::DefinitionExt def, IRBlock input, Ssa::PhiNode phi
|
instructionGuardChecks(g, def.getARead().asIndirectOperand(indirectionIndex).getDef(), branch) and
guardControlsPhiInput(g, branch, def, pragma[only_bind_into](input),
pragma[only_bind_into](phi)) and
result = TSsaPhiInputNode(phi, input)
)
}
}

/**
Expand Down
9 changes: 9 additions & 0 deletions cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
bool checkArgument(int* x);

void sink(int);

void testCheckArgument(int* p) {
if (checkArgument(p)) {
sink(*p); // $ barrier barrier=1
}
}
Empty file.
42 changes: 42 additions & 0 deletions cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import cpp
import semmle.code.cpp.dataflow.new.DataFlow
import semmle.code.cpp.controlflow.IRGuards
import utils.test.InlineExpectationsTest

predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boolean branch) {
exists(CallInstruction call |
call.getStaticCallTarget().hasName("checkArgument") and
checked = call.getAnArgument() and
gc.comparesEq(call.getAUse(), 0, false, any(BooleanValue bv | bv.getValue() = branch))
)
}

module BarrierGuard = DataFlow::InstructionBarrierGuard<instructionGuardChecks/3>;

predicate indirectBarrierGuard(DataFlow::Node node, int indirectionIndex) {
node = BarrierGuard::getAnIndirectBarrierNode(indirectionIndex)
}

predicate barrierGuard(DataFlow::Node node) { node = BarrierGuard::getABarrierNode() }

module Test implements TestSig {
string getARelevantTag() { result = "barrier" }

predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node node |
barrierGuard(node) and
value = ""
or
exists(int indirectionIndex |
indirectBarrierGuard(node, indirectionIndex) and
value = indirectionIndex.toString()
)
|
tag = "barrier" and
element = node.toString() and
location = node.getLocation()
)
}
}

import MakeTest<Test>

0 comments on commit 0ff37f1

Please sign in to comment.