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
4 changes: 4 additions & 0 deletions cpp/ql/lib/change-notes/2026-02-24-barrier-guards.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: breaking
---
* CodeQL version 2.24.2 accidentially introduced a syntactical breaking change to `BarrierGuard<...>::getAnIndirectBarrierNode` and `InstructionBarrierGuard<...>::getAnIndirectBarrierNode`. These breaking changes have now been reverted so that the original code compiles again.
64 changes: 62 additions & 2 deletions cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2641,7 +2641,54 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
exists(unit)
}

import ParameterizedBarrierGuard<Unit, guardChecks/4>
private module P = ParameterizedBarrierGuard<Unit, guardChecks/4>;

predicate getABarrierNode = P::getABarrierNode/0;

/**
* Gets an indirect expression node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check.
*
* For example, given the following code:
* ```cpp
* int* p;
* // ...
* *p = source();
* if(is_safe_pointer(p)) {
* sink(*p);
* }
* ```
* and the following barrier guard check:
* ```ql
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
* exists(Call call |
* g.getUnconvertedResultExpression() = call and
* call.getTarget().hasName("is_safe_pointer") and
* e = call.getAnArgument() and
* branch = true
* )
* }
* ```
* implementing `isBarrier` as:
* ```ql
* predicate isBarrier(DataFlow::Node barrier) {
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getAnIndirectBarrierNode(1)
* }
* ```
* will block flow from `x = source()` to `sink(x)`.
*
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
result = P::getAnIndirectBarrierNode(indirectionIndex, _)
}

/**
* Gets an indirect expression node that is safely guarded by the given guard check.
*
* See `getAnIndirectBarrierNode/1` for examples.
*/
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}

private module InstrWithParam<ParamSig P> {
Expand Down Expand Up @@ -2752,7 +2799,20 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
exists(unit)
}

import ParameterizedInstructionBarrierGuard<Unit, instructionGuardChecks/4>
private module P = ParameterizedInstructionBarrierGuard<Unit, instructionGuardChecks/4>;

predicate getABarrierNode = P::getABarrierNode/0;

/**
* Gets an indirect node with indirection index `indirectionIndex` that is
* safely guarded by the given guard check.
*/
Node getAnIndirectBarrierNode(int indirectionIndex) {
result = P::getAnIndirectBarrierNode(indirectionIndex, _)
}

/** Gets an indirect node that is safely guarded by the given guard check. */
Node getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
}

/**
Expand Down
5 changes: 4 additions & 1 deletion cpp/ql/test/library-tests/dataflow/ir-barrier-guards/test.ql
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ predicate instructionGuardChecks(IRGuardCondition gc, Instruction checked, boole
module BarrierGuard = DataFlow::InstructionBarrierGuard<instructionGuardChecks/3>;

predicate indirectBarrierGuard(DataFlow::Node node, string s) {
node = BarrierGuard::getAnIndirectBarrierNode(_) and
// This any(...) could technically be removed, but it helps us verify that we don't
// accidentially change the API of this predicate (for instance, by having
// the column be a unit parameter).
node = BarrierGuard::getAnIndirectBarrierNode(any(int indirectionIndex)) and
if node.isGLValue()
then s = "glval<" + node.getType().toString().replaceAll(" ", "") + ">"
else s = node.getType().toString().replaceAll(" ", "")
Expand Down