Skip to content

Commit 0e66d08

Browse files
authored
Merge pull request github#3785 from MathiasVP/dataflow-operand-nodes
C++: Operands as dataflow nodes
2 parents 0bbbfe5 + 5fbf305 commit 0e66d08

File tree

4 files changed

+857
-11
lines changed

4 files changed

+857
-11
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,4 @@ predicate isImmutableOrUnobservable(Node n) {
303303
}
304304

305305
/** Holds if `n` should be hidden from path explanations. */
306-
predicate nodeIsHidden(Node n) { none() }
306+
predicate nodeIsHidden(Node n) { n instanceof OperandNode }

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

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313

1414
private newtype TIRDataFlowNode =
1515
TInstructionNode(Instruction i) or
16+
TOperandNode(Operand op) or
1617
TVariableNode(Variable var)
1718

1819
/**
@@ -37,6 +38,9 @@ class Node extends TIRDataFlowNode {
3738
/** Gets the instruction corresponding to this node, if any. */
3839
Instruction asInstruction() { result = this.(InstructionNode).getInstruction() }
3940

41+
/** Gets the operands corresponding to this node, if any. */
42+
Operand asOperand() { result = this.(OperandNode).getOperand() }
43+
4044
/**
4145
* Gets the non-conversion expression corresponding to this node, if any. If
4246
* this node strictly (in the sense of `asConvertedExpr`) corresponds to a
@@ -132,6 +136,28 @@ class InstructionNode extends Node, TInstructionNode {
132136
}
133137
}
134138

139+
/**
140+
* An operand, viewed as a node in a data flow graph.
141+
*/
142+
class OperandNode extends Node, TOperandNode {
143+
Operand op;
144+
145+
OperandNode() { this = TOperandNode(op) }
146+
147+
/** Gets the operand corresponding to this node. */
148+
Operand getOperand() { result = op }
149+
150+
override Declaration getEnclosingCallable() { result = this.getFunction() }
151+
152+
override Function getFunction() { result = op.getUse().getEnclosingFunction() }
153+
154+
override Type getType() { result = op.getType() }
155+
156+
override Location getLocation() { result = op.getLocation() }
157+
158+
override string toString() { result = this.getOperand().toString() }
159+
}
160+
135161
/**
136162
* An expression, viewed as a node in a data flow graph.
137163
*/
@@ -291,7 +317,7 @@ abstract class PostUpdateNode extends InstructionNode {
291317
* setY(&x); // a partial definition of the object `x`.
292318
* ```
293319
*/
294-
abstract private class PartialDefinitionNode extends PostUpdateNode, TInstructionNode {
320+
abstract private class PartialDefinitionNode extends PostUpdateNode {
295321
abstract Expr getDefinedExpr();
296322
}
297323

@@ -306,11 +332,11 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
306332
)
307333
}
308334

309-
// There might be multiple `ChiInstructions` that has a particular instruction as
310-
// the total operand - so this definition gives consistency errors in
311-
// DataFlowImplConsistency::Consistency. However, it's not clear what (if any) implications
312-
// this consistency failure has.
313-
override Node getPreUpdateNode() { result.asInstruction() = instr.getTotal() }
335+
// By using an operand as the result of this predicate we avoid the dataflow inconsistency errors
336+
// caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause
337+
// a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node
338+
// into a big step.
339+
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
314340

315341
override Expr getDefinedExpr() {
316342
result = field.getObjectAddress().getUnconvertedResultExpression()
@@ -482,7 +508,11 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
482508
* data flow. It may have less flow than the `localFlowStep` predicate.
483509
*/
484510
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
511+
// Instruction -> Instruction flow
485512
simpleInstructionLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asInstruction())
513+
or
514+
// Operand -> Instruction flow
515+
simpleOperandLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
486516
}
487517

488518
pragma[noinline]
@@ -494,6 +524,16 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) {
494524
)
495525
}
496526

527+
private predicate simpleOperandLocalFlowStep(Operand opFrom, Instruction iTo) {
528+
// Certain dataflow steps (for instance `PostUpdateNode.getPreUpdateNode()`) generates flow to
529+
// operands, so we include dataflow from those operands to the "result" of the instruction (i.e., to
530+
// the instruction itself).
531+
exists(PostUpdateNode post |
532+
opFrom = post.getPreUpdateNode().asOperand() and
533+
iTo.getAnOperand() = opFrom
534+
)
535+
}
536+
497537
cached
498538
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
499539
iTo.(CopyInstruction).getSourceValue() = iFrom

cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-ir-consistency.expected

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ localCallNodes
2727
postIsNotPre
2828
postHasUniquePre
2929
uniquePostUpdate
30-
| ref.cpp:83:5:83:17 | Chi | Node has multiple PostUpdateNodes. |
31-
| ref.cpp:109:5:109:22 | Chi | Node has multiple PostUpdateNodes. |
3230
postIsInSameCallable
3331
reverseRead
3432
storeIsPostUpdate

0 commit comments

Comments
 (0)