Skip to content

Commit 1fab97b

Browse files
authored
Merge pull request #20149 from MathiasVP/expose-definition-from-dataflow-ssa
C++: Expose SSA definitions from dataflow
2 parents 492e27b + 0e9286d commit 1fab97b

File tree

11 files changed

+181
-68
lines changed

11 files changed

+181
-68
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* Exposed various SSA-related classes (`Definition`, `PhiNode`, `ExplicitDefinition`, `DirectExplicitDefinition`, and `IndirectExplicitDefinition`) which were previously only usable inside the internal dataflow directory.

cpp/ql/lib/semmle/code/cpp/controlflow/SSA.qll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ class StandardSsa extends SsaHelper {
1515
}
1616

1717
/**
18+
* NOTE: If possible, prefer the SSA classes exposed by the new dataflow
19+
* library:
20+
* ```
21+
* import semmle.code.cpp.dataflow.new.DataFlow
22+
* // use `DataFlow::Ssa::Definition`
23+
* ```
24+
*
1825
* A definition of one or more SSA variables, including phi node definitions.
1926
* An _SSA variable_, as defined in the literature, is effectively the pair of
2027
* an `SsaDefinition d` and a `StackVariable v`, written `(d, v)` in this

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

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
private import cpp
22
private import semmle.code.cpp.ir.IR
3-
private import semmle.code.cpp.ir.dataflow.DataFlow
43
private import DataFlowPrivate
54
private import DataFlowUtil
65
private import DataFlowImplCommon as DataFlowImplCommon
@@ -60,7 +59,7 @@ private module VirtualDispatch {
6059
* `resolve` predicate to stitch that information together and resolve the
6160
* call.
6261
*/
63-
abstract DataFlow::Node getDispatchValue();
62+
abstract Node getDispatchValue();
6463

6564
/** Gets a candidate target for this call. */
6665
abstract Function resolve();
@@ -72,17 +71,13 @@ private module VirtualDispatch {
7271
* parameter is true when the search is allowed to continue backwards into
7372
* a parameter; non-recursive callers should pass `_` for `allowFromArg`.
7473
*/
75-
predicate flowsFrom(DataFlow::Node src, boolean allowFromArg) {
74+
predicate flowsFrom(Node src, boolean allowFromArg) {
7675
src = this.getDispatchValue() and allowFromArg = true
7776
or
78-
exists(DataFlow::Node other, boolean allowOtherFromArg |
79-
this.flowsFrom(other, allowOtherFromArg)
80-
|
77+
exists(Node other, boolean allowOtherFromArg | this.flowsFrom(other, allowOtherFromArg) |
8178
// Call argument
8279
exists(DataFlowCall call, Position i |
83-
other
84-
.(DataFlow::ParameterNode)
85-
.isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
80+
other.(ParameterNode).isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
8681
src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i)))
8782
) and
8883
allowOtherFromArg = true and
@@ -96,7 +91,7 @@ private module VirtualDispatch {
9691
allowFromArg = false
9792
or
9893
// Local flow
99-
DataFlow::localFlowStep(src, other) and
94+
localFlowStep(src, other) and
10095
allowFromArg = allowOtherFromArg
10196
or
10297
// Flow from global variable to load.
@@ -159,11 +154,11 @@ private module VirtualDispatch {
159154
private class DataSensitiveExprCall extends DataSensitiveCall {
160155
DataSensitiveExprCall() { not exists(this.getStaticCallTarget()) }
161156

162-
override DataFlow::Node getDispatchValue() { result.asOperand() = this.getCallTargetOperand() }
157+
override Node getDispatchValue() { result.asOperand() = this.getCallTargetOperand() }
163158

164159
override Function resolve() {
165160
exists(FunctionInstruction fi |
166-
this.flowsFrom(DataFlow::instructionNode(fi), _) and
161+
this.flowsFrom(instructionNode(fi), _) and
167162
result = fi.getFunctionSymbol()
168163
) and
169164
(
@@ -186,7 +181,7 @@ private module VirtualDispatch {
186181
)
187182
}
188183

189-
override DataFlow::Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
184+
override Node getDispatchValue() { result.asInstruction() = this.getArgument(-1) }
190185

191186
override MemberFunction resolve() {
192187
exists(Class overridingClass |
@@ -213,7 +208,7 @@ private module VirtualDispatch {
213208
pragma[noinline]
214209
private predicate hasFlowFromCastFrom(Class derivedClass) {
215210
exists(ConvertToBaseInstruction toBase |
216-
this.flowsFrom(DataFlow::instructionNode(toBase), _) and
211+
this.flowsFrom(instructionNode(toBase), _) and
217212
derivedClass = toBase.getDerivedClass()
218213
)
219214
}
@@ -270,7 +265,7 @@ private predicate mayBenefitFromCallContext(
270265
exists(InitializeParameterInstruction init |
271266
not exists(call.getStaticCallTarget()) and
272267
init.getEnclosingFunction() = f.getUnderlyingCallable() and
273-
call.flowsFrom(DataFlow::instructionNode(init), _) and
268+
call.flowsFrom(instructionNode(init), _) and
274269
init.getParameter().getIndex() = arg
275270
)
276271
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ private import semmle.code.cpp.ir.IR
44
private import DataFlowDispatch
55
private import semmle.code.cpp.ir.internal.IRCppLanguage
66
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
7-
private import SsaInternals as Ssa
7+
private import SsaImpl as Ssa
88
private import DataFlowImplCommon as DataFlowImplCommon
99
private import codeql.util.Unit
1010
private import Node0ToString

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

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1414
private import DataFlowPrivate
1515
private import ModelUtil
16-
private import SsaInternals as Ssa
16+
private import SsaImpl as SsaImpl
1717
private import DataFlowImplCommon as DataFlowImplCommon
1818
private import codeql.util.Unit
1919
private import Node0ToString
@@ -39,38 +39,39 @@ private newtype TIRDataFlowNode =
3939
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
4040
TGlobalLikeVariableNode(GlobalLikeVariable var, int indirectionIndex) {
4141
indirectionIndex =
42-
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
42+
[getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
4343
} or
4444
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
4545
operand = any(FieldAddress fa).getObjectAddressOperand() and
46-
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
46+
indirectionIndex =
47+
[0 .. SsaImpl::countIndirectionsForCppType(SsaImpl::getLanguageType(operand))]
4748
or
48-
Ssa::isModifiableByCall(operand, indirectionIndex)
49+
SsaImpl::isModifiableByCall(operand, indirectionIndex)
4950
} or
50-
TSsaSynthNode(Ssa::SynthNode n) or
51+
TSsaSynthNode(SsaImpl::SynthNode n) or
5152
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
5253
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
53-
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
54+
SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
5455
} or
5556
TRawIndirectInstruction0(Node0Impl node, int indirectionIndex) {
5657
not exists(node.asOperand()) and
57-
Ssa::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
58+
SsaImpl::hasRawIndirectInstruction(node.asInstruction(), indirectionIndex)
5859
} or
5960
TFinalParameterNode(Parameter p, int indirectionIndex) {
60-
exists(Ssa::FinalParameterUse use |
61+
exists(SsaImpl::FinalParameterUse use |
6162
use.getParameter() = p and
6263
use.getIndirectionIndex() = indirectionIndex
6364
)
6465
} or
65-
TFinalGlobalValue(Ssa::GlobalUse globalUse) or
66-
TInitialGlobalValue(Ssa::GlobalDef globalUse) or
66+
TFinalGlobalValue(SsaImpl::GlobalUse globalUse) or
67+
TInitialGlobalValue(SsaImpl::GlobalDef globalUse) or
6768
TBodyLessParameterNodeImpl(Parameter p, int indirectionIndex) {
6869
// Rule out parameters of catch blocks.
6970
not exists(p.getCatchBlock()) and
7071
// We subtract one because `getMaxIndirectionsForType` returns the maximum
7172
// indirection for a glvalue of a given type, and this doesn't apply to
7273
// parameters.
73-
indirectionIndex = [0 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
74+
indirectionIndex = [0 .. SsaImpl::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] and
7475
not any(InitializeParameterInstruction init).getParameter() = p
7576
} or
7677
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn)
@@ -81,7 +82,7 @@ private newtype TIRDataFlowNode =
8182
class FieldAddress extends Operand {
8283
FieldAddressInstruction fai;
8384

84-
FieldAddress() { fai = this.getDef() and not Ssa::ignoreOperand(this) }
85+
FieldAddress() { fai = this.getDef() and not SsaImpl::ignoreOperand(this) }
8586

8687
/** Gets the field associated with this instruction. */
8788
Field getField() { result = fai.getField() }
@@ -126,7 +127,7 @@ predicate conversionFlow(
126127
)
127128
or
128129
additional = true and
129-
Ssa::isAdditionalConversionFlow(opFrom, instrTo)
130+
SsaImpl::isAdditionalConversionFlow(opFrom, instrTo)
130131
)
131132
or
132133
isPointerArith = true and
@@ -183,7 +184,7 @@ class Node extends TIRDataFlowNode {
183184
or
184185
this.asOperand().getUse() = block.getInstruction(i)
185186
or
186-
exists(Ssa::SynthNode ssaNode |
187+
exists(SsaImpl::SynthNode ssaNode |
187188
this.(SsaSynthNode).getSynthNode() = ssaNode and
188189
ssaNode.getBasicBlock() = block and
189190
ssaNode.getIndex() = i
@@ -364,10 +365,10 @@ class Node extends TIRDataFlowNode {
364365
* pointed to by `p`.
365366
*/
366367
Expr asDefinition(boolean uncertain) {
367-
exists(StoreInstruction store, Ssa::Definition def |
368+
exists(StoreInstruction store, SsaImpl::Definition def |
368369
store = this.asInstruction() and
369370
result = asDefinitionImpl(store) and
370-
Ssa::defToNode(this, def, _) and
371+
SsaImpl::defToNode(this, def, _) and
371372
if def.isCertain() then uncertain = false else uncertain = true
372373
)
373374
}
@@ -627,7 +628,7 @@ class OperandNode extends Node, Node0 {
627628
* For example, `stripPointers(int*&)` is `int*` and `stripPointers(int*)` is `int`.
628629
*/
629630
Type stripPointer(Type t) {
630-
result = any(Ssa::Indirection ind | ind.getType() = t).getBaseType()
631+
result = any(SsaImpl::Indirection ind | ind.getType() = t).getBaseType()
631632
or
632633
result = t.(PointerToMemberType).getBaseType()
633634
or
@@ -694,12 +695,12 @@ class PostFieldUpdateNode extends PostUpdateNodeImpl {
694695
* in a data flow graph.
695696
*/
696697
class SsaSynthNode extends Node, TSsaSynthNode {
697-
Ssa::SynthNode node;
698+
SsaImpl::SynthNode node;
698699

699700
SsaSynthNode() { this = TSsaSynthNode(node) }
700701

701702
/** Gets the synthesized SSA node associated with this node. */
702-
Ssa::SynthNode getSynthNode() { result = node }
703+
SsaImpl::SynthNode getSynthNode() { result = node }
703704

704705
override DataFlowCallable getEnclosingCallable() {
705706
result.asSourceCallable() = this.getFunction()
@@ -782,12 +783,12 @@ class SideEffectOperandNode extends Node instanceof IndirectOperand {
782783
* from a function body.
783784
*/
784785
class FinalGlobalValue extends Node, TFinalGlobalValue {
785-
Ssa::GlobalUse globalUse;
786+
SsaImpl::GlobalUse globalUse;
786787

787788
FinalGlobalValue() { this = TFinalGlobalValue(globalUse) }
788789

789790
/** Gets the underlying SSA use. */
790-
Ssa::GlobalUse getGlobalUse() { result = globalUse }
791+
SsaImpl::GlobalUse getGlobalUse() { result = globalUse }
791792

792793
override DataFlowCallable getEnclosingCallable() {
793794
result.asSourceCallable() = this.getFunction()
@@ -814,12 +815,12 @@ class FinalGlobalValue extends Node, TFinalGlobalValue {
814815
* a function body.
815816
*/
816817
class InitialGlobalValue extends Node, TInitialGlobalValue {
817-
Ssa::GlobalDef globalDef;
818+
SsaImpl::GlobalDef globalDef;
818819

819820
InitialGlobalValue() { this = TInitialGlobalValue(globalDef) }
820821

821822
/** Gets the underlying SSA definition. */
822-
Ssa::GlobalDef getGlobalDef() { result = globalDef }
823+
SsaImpl::GlobalDef getGlobalDef() { result = globalDef }
823824

824825
override DataFlowCallable getEnclosingCallable() {
825826
result.asSourceCallable() = this.getFunction()
@@ -1288,11 +1289,11 @@ class UninitializedNode extends Node {
12881289
LocalVariable v;
12891290

12901291
UninitializedNode() {
1291-
exists(Ssa::Definition def, Ssa::SourceVariable sv |
1292+
exists(SsaImpl::Definition def, SsaImpl::SourceVariable sv |
12921293
def.getIndirectionIndex() = 0 and
12931294
def.getValue().asInstruction() instanceof UninitializedInstruction and
1294-
Ssa::defToNode(this, def, sv) and
1295-
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
1295+
SsaImpl::defToNode(this, def, sv) and
1296+
v = sv.getBaseVariable().(SsaImpl::BaseIRVariable).getIRVariable().getAst()
12961297
)
12971298
}
12981299

@@ -1722,7 +1723,7 @@ private module Cached {
17221723
cached
17231724
predicate flowsToBackEdge(Node n) {
17241725
exists(Node succ, IRBlock bb1, IRBlock bb2 |
1725-
Ssa::ssaFlow(n, succ) and
1726+
SsaImpl::ssaFlow(n, succ) and
17261727
bb1 = n.getBasicBlock() and
17271728
bb2 = succ.getBasicBlock() and
17281729
bb1 != bb2 and
@@ -1820,7 +1821,7 @@ private module Cached {
18201821
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
18211822
(
18221823
// Def-use/Use-use flow
1823-
Ssa::ssaFlow(nodeFrom, nodeTo)
1824+
SsaImpl::ssaFlow(nodeFrom, nodeTo)
18241825
or
18251826
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
18261827
or
@@ -1833,7 +1834,7 @@ private module Cached {
18331834
|
18341835
simpleOperandLocalFlowStep(iFrom, opTo) and
18351836
// Omit when the instruction node also represents the operand.
1836-
not iFrom = Ssa::getIRRepresentationOfOperand(opTo)
1837+
not iFrom = SsaImpl::getIRRepresentationOfOperand(opTo)
18371838
)
18381839
or
18391840
// Indirect operand -> (indirect) instruction flow
@@ -1906,7 +1907,7 @@ private module Cached {
19061907
// We also want a write coming out of an `OutNode` to flow `nodeTo`.
19071908
// This is different from `reverseFlowInstruction` since `nodeFrom` can never
19081909
// be an `OutNode` when it's defined by an instruction.
1909-
Ssa::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
1910+
SsaImpl::outNodeHasAddressAndIndex(nodeFrom, address, indirectionIndex)
19101911
)
19111912
}
19121913

@@ -2099,7 +2100,7 @@ private newtype TContent =
20992100
TFieldContent(Field f, int indirectionIndex) {
21002101
// the indirection index for field content starts at 1 (because `TFieldContent` is thought of as
21012102
// the address of the field, `FieldAddress` in the IR).
2102-
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(f.getUnspecifiedType())] and
2103+
indirectionIndex = [1 .. SsaImpl::getMaxIndirectionsForType(f.getUnspecifiedType())] and
21032104
// Reads and writes of union fields are tracked using `UnionContent`.
21042105
not f.getDeclaringType() instanceof Union
21052106
} or
@@ -2111,7 +2112,9 @@ private newtype TContent =
21112112
// field can be read by any read of the union's fields. Again, the indirection index
21122113
// is 1-based (because 0 is considered the address).
21132114
indirectionIndex =
2114-
[1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))]
2115+
[1 .. max(SsaImpl::getMaxIndirectionsForType(getAFieldWithSize(u, bytes)
2116+
.getUnspecifiedType())
2117+
)]
21152118
)
21162119
} or
21172120
TElementContent(int indirectionIndex) {
@@ -2354,7 +2357,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
23542357
controls(g, result, edge)
23552358
)
23562359
or
2357-
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
2360+
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
23582361
}
23592362

23602363
/**
@@ -2453,7 +2456,7 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
24532456
)
24542457
or
24552458
result =
2456-
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
2459+
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
24572460
}
24582461
}
24592462

@@ -2490,7 +2493,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
24902493
controls(g, result, edge)
24912494
)
24922495
or
2493-
result = Ssa::BarrierGuard<guardChecksNode/3>::getABarrierNode()
2496+
result = SsaImpl::BarrierGuard<guardChecksNode/3>::getABarrierNode()
24942497
}
24952498

24962499
bindingset[value, n]
@@ -2520,7 +2523,7 @@ module InstructionBarrierGuard<instructionGuardChecksSig/3 instructionGuardCheck
25202523
)
25212524
or
25222525
result =
2523-
Ssa::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
2526+
SsaImpl::BarrierGuardWithIntParam<guardChecksIndirectNode/4>::getABarrierNode(indirectionIndex)
25242527
}
25252528
}
25262529

@@ -2576,3 +2579,16 @@ Function getARuntimeTarget(Call call) {
25762579
result = DataFlowImplCommon::viableCallableLambda(dfCall, _).asSourceCallable()
25772580
)
25782581
}
2582+
2583+
/** A module that provides static single assignment (SSA) information. */
2584+
module Ssa {
2585+
class Definition = SsaImpl::Definition;
2586+
2587+
class ExplicitDefinition = SsaImpl::ExplicitDefinition;
2588+
2589+
class DirectExplicitDefinition = SsaImpl::DirectExplicitDefinition;
2590+
2591+
class IndirectExplicitDefinition = SsaImpl::IndirectExplicitDefinition;
2592+
2593+
class PhiNode = SsaImpl::PhiNode;
2594+
}

0 commit comments

Comments
 (0)