Skip to content

Commit ecb5e7a

Browse files
committed
C++: Fix spurious ExprNode fanout in DataFlowIntegration.
1 parent b5a2f5d commit ecb5e7a

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

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

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,6 @@ abstract class UseImpl extends TUseImpl {
296296
)
297297
}
298298

299-
final predicate hasNodeAndSourceVariable(Node n, SourceVariable sv) {
300-
sv = this.getSourceVariable() and
301-
n = this.getNode()
302-
}
303-
304299
/**
305300
* Holds if this use is guaranteed to read the
306301
* associated variable.
@@ -966,17 +961,22 @@ private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
966961
private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationInputSig {
967962
private import codeql.util.Void
968963

969-
final private class UseImplFinal = UseImpl;
964+
class Expr extends Instruction {
965+
Expr() {
966+
exists(IRBlock bb, int i |
967+
variableRead(bb, i, _, true) and
968+
this = bb.getInstruction(i)
969+
)
970+
}
970971

971-
class Expr extends UseImplFinal {
972-
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this.hasIndexInBlock(bb, i) }
972+
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { bb.getInstruction(i) = this }
973973
}
974974

975975
Expr getARead(SsaImpl::Definition def) {
976976
exists(SourceVariable v, IRBlock bb, int i |
977977
ssaDefReachesRead(v, def, bb, i) and
978978
variableRead(bb, i, v, true) and
979-
result.hasIndexInBlock(bb, i, v)
979+
result.hasCfgNode(bb, i)
980980
)
981981
}
982982

@@ -1028,21 +1028,38 @@ signature predicate guardChecksNodeSig(
10281028
);
10291029

10301030
module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
1031+
private predicate ssaDefReachesCertainUse(Definition def, UseImpl use) {
1032+
exists(SourceVariable v, IRBlock bb, int i |
1033+
use.hasIndexInBlock(bb, i, v) and
1034+
variableRead(bb, i, v, true) and
1035+
ssaDefReachesRead(v, def, bb, i)
1036+
)
1037+
}
1038+
10311039
private predicate guardChecks(
1032-
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch,
1033-
int indirectionIndex
1040+
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, boolean branch, int indirectionIndex
10341041
) {
1035-
guardChecksNode(g, e.getNode(), branch, indirectionIndex)
1042+
exists(UseImpl use |
1043+
guardChecksNode(g, use.getNode(), branch, indirectionIndex) and
1044+
ssaDefReachesCertainUse(def, use)
1045+
)
10361046
}
10371047

10381048
Node getABarrierNode(int indirectionIndex) {
1039-
exists(DataFlowIntegrationImpl::Node n |
1040-
n =
1041-
DataFlowIntegrationImpl::BarrierGuardWithState<int, guardChecks/4>::getABarrierNode(indirectionIndex)
1042-
|
1043-
n = result.(SsaSynthNode).getSynthNode()
1044-
or
1045-
n.(DataFlowIntegrationImpl::ExprNode).getExpr().getNode() = result
1049+
// Only get the SynthNodes from the shared implementation, as the ExprNodes cannot
1050+
// be matched on SourceVariable.
1051+
result.(SsaSynthNode).getSynthNode() =
1052+
DataFlowIntegrationImpl::BarrierGuardDefWithState<int, guardChecks/4>::getABarrierNode(indirectionIndex)
1053+
or
1054+
// Calculate the guarded UseImpls corresponding to ExprNodes directly.
1055+
exists(DataFlowIntegrationInput::Guard g, boolean branch, Definition def, IRBlock bb |
1056+
guardChecks(g, def, branch, indirectionIndex) and
1057+
exists(UseImpl use |
1058+
ssaDefReachesCertainUse(def, use) and
1059+
use.getBlock() = bb and
1060+
DataFlowIntegrationInput::guardControlsBlock(g, bb, branch) and
1061+
result = use.getNode()
1062+
)
10461063
)
10471064
}
10481065
}
@@ -1064,7 +1081,12 @@ pragma[inline_late]
10641081
DataFlowIntegrationImpl::Node fromDfNode(Node n, SourceVariable v) {
10651082
result = n.(SsaSynthNode).getSynthNode()
10661083
or
1067-
result.(DataFlowIntegrationImpl::ExprNode).getExpr().hasNodeAndSourceVariable(n, v)
1084+
exists(UseImpl use, IRBlock bb, int i |
1085+
result.(DataFlowIntegrationImpl::ExprNode).getExpr().hasCfgNode(bb, i) and
1086+
use.hasIndexInBlock(bb, i, v) and
1087+
use.isCertain() and
1088+
use.getNode() = n
1089+
)
10681090
or
10691091
defToNode(n, result.(DataFlowIntegrationImpl::SsaDefinitionNode).getDefinition())
10701092
}

shared/ssa/codeql/ssa/Ssa.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,6 +1897,14 @@ module Make<LocationSig Location, InputSig<Location> Input> {
18971897
signature predicate guardChecksSig(
18981898
DfInput::Guard g, DfInput::Expr e, boolean branch, State state
18991899
);
1900+
1901+
/**
1902+
* Holds if the guard `g` validates the SSA definition `def` upon
1903+
* evaluating to `branch`, blocking flow in the given `state`.
1904+
*/
1905+
signature predicate guardChecksDefSig(
1906+
DfInput::Guard g, Definition def, boolean branch, State state
1907+
);
19001908
}
19011909

19021910
/**
@@ -1933,6 +1941,20 @@ module Make<LocationSig Location, InputSig<Location> Input> {
19331941
guardChecks(g, DfInput::getARead(def), branch, state)
19341942
}
19351943

1944+
private module Barrier = BarrierGuardDefWithState<State, guardChecksSsaDef/4>;
1945+
1946+
predicate getABarrierNode = Barrier::getABarrierNode/1;
1947+
}
1948+
1949+
/**
1950+
* Provides a set of barrier nodes for a guard that validates an expression.
1951+
*
1952+
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
1953+
* in data flow and taint tracking.
1954+
*/
1955+
module BarrierGuardDefWithState<
1956+
StateSig State, WithState<State>::guardChecksDefSig/4 guardChecksSsaDef>
1957+
{
19361958
/** Gets a node that is safely guarded by the given guard check. */
19371959
pragma[nomagic]
19381960
Node getABarrierNode(State state) {

0 commit comments

Comments
 (0)