Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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`.
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
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>