Skip to content

Commit e539aca

Browse files
committed
C++: Add an interface for blocking flow out of functions that reach a certain argument.
1 parent 525f271 commit e539aca

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ private import codeql.ssa.Ssa as SsaImplCommon
22
private import semmle.code.cpp.ir.IR
33
private import DataFlowUtil
44
private import DataFlowImplCommon as DataFlowImplCommon
5+
private import semmle.code.cpp.ir.dataflow.internal.ModelUtil
56
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
67
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
8+
private import semmle.code.cpp.models.interfaces.FlowOutBarrier as FOB
9+
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as FIO
710
private import semmle.code.cpp.ir.internal.IRCppLanguage
811
private import DataFlowPrivate
912
private import ssa0.SsaInternals as SsaInternals0
@@ -784,10 +787,30 @@ private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
784787
)
785788
}
786789

790+
/**
791+
* Holds if there should not be use-use flow out of `n` (or a conversion that
792+
* flows to `n`).
793+
*/
794+
private predicate modeledFlowBarrier(Node n) {
795+
exists(FIO::FunctionInput input, CallInstruction call |
796+
call.getStaticCallTarget().(FOB::FlowOutBarrierFunction).isFlowOutBarrier(input) and
797+
n = callInput(call, input)
798+
)
799+
or
800+
exists(Operand operand, Instruction instr, Node n0, int indirectionIndex |
801+
modeledFlowBarrier(n0) and
802+
nodeHasInstruction(n0, instr, indirectionIndex) and
803+
conversionFlow(operand, instr, false, _) and
804+
nodeHasOperand(n, operand, indirectionIndex)
805+
)
806+
}
807+
787808
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
788809
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
789810
exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
790-
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and nodeFrom != nodeTo
811+
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
812+
not modeledFlowBarrier(nFrom) and
813+
nodeFrom != nodeTo
791814
|
792815
if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
793816
)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Provides an abstract class for blocking flow out of functions. To use this
3+
* QL library, create a QL class extending `FlowOutBarrierFunction` with a
4+
* characteristic predicate that selects the function or set of functions you
5+
* are modeling. Within that class, override the predicates provided by
6+
* `FlowOutBarrierFunction` to match the flow within that function.
7+
*/
8+
9+
import semmle.code.cpp.Function
10+
import FunctionInputsAndOutputs
11+
12+
/**
13+
* A library function for which flow should not continue after reaching one
14+
* of its inputs.
15+
*
16+
* For example, since `std::swap(a, b)` swaps the values pointed to by `a`
17+
* and `b` there should not be use-use flow out of `a` or `b`.
18+
*/
19+
abstract class FlowOutBarrierFunction extends Function {
20+
/**
21+
* Holds if use-use flow should not continue onwards after reaching
22+
* the argument, qualifier, or buffer represented by `input`.
23+
*/
24+
pragma[nomagic]
25+
abstract predicate isFlowOutBarrier(FunctionInput input);
26+
}

0 commit comments

Comments
 (0)