@@ -13,6 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
13
13
14
14
private newtype TIRDataFlowNode =
15
15
TInstructionNode ( Instruction i ) or
16
+ TOperandNode ( Operand op ) or
16
17
TVariableNode ( Variable var )
17
18
18
19
/**
@@ -37,6 +38,9 @@ class Node extends TIRDataFlowNode {
37
38
/** Gets the instruction corresponding to this node, if any. */
38
39
Instruction asInstruction ( ) { result = this .( InstructionNode ) .getInstruction ( ) }
39
40
41
+ /** Gets the operands corresponding to this node, if any. */
42
+ Operand asOperand ( ) { result = this .( OperandNode ) .getOperand ( ) }
43
+
40
44
/**
41
45
* Gets the non-conversion expression corresponding to this node, if any. If
42
46
* this node strictly (in the sense of `asConvertedExpr`) corresponds to a
@@ -132,6 +136,28 @@ class InstructionNode extends Node, TInstructionNode {
132
136
}
133
137
}
134
138
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
+
135
161
/**
136
162
* An expression, viewed as a node in a data flow graph.
137
163
*/
@@ -291,7 +317,7 @@ abstract class PostUpdateNode extends InstructionNode {
291
317
* setY(&x); // a partial definition of the object `x`.
292
318
* ```
293
319
*/
294
- abstract private class PartialDefinitionNode extends PostUpdateNode , TInstructionNode {
320
+ abstract private class PartialDefinitionNode extends PostUpdateNode {
295
321
abstract Expr getDefinedExpr ( ) ;
296
322
}
297
323
@@ -306,11 +332,11 @@ private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
306
332
)
307
333
}
308
334
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 ( ) }
314
340
315
341
override Expr getDefinedExpr ( ) {
316
342
result = field .getObjectAddress ( ) .getUnconvertedResultExpression ( )
@@ -482,7 +508,11 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
482
508
* data flow. It may have less flow than the `localFlowStep` predicate.
483
509
*/
484
510
predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
511
+ // Instruction -> Instruction flow
485
512
simpleInstructionLocalFlowStep ( nodeFrom .asInstruction ( ) , nodeTo .asInstruction ( ) )
513
+ or
514
+ // Operand -> Instruction flow
515
+ simpleOperandLocalFlowStep ( nodeFrom .asOperand ( ) , nodeTo .asInstruction ( ) )
486
516
}
487
517
488
518
pragma [ noinline]
@@ -494,6 +524,16 @@ private predicate getFieldSizeOfClass(Class c, Type type, int size) {
494
524
)
495
525
}
496
526
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
+
497
537
cached
498
538
private predicate simpleInstructionLocalFlowStep ( Instruction iFrom , Instruction iTo ) {
499
539
iTo .( CopyInstruction ) .getSourceValue ( ) = iFrom
0 commit comments