@@ -13,6 +13,7 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313
1414private 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 */
484510predicate 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
488518pragma [ 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+
497537cached
498538private predicate simpleInstructionLocalFlowStep ( Instruction iFrom , Instruction iTo ) {
499539 iTo .( CopyInstruction ) .getSourceValue ( ) = iFrom
0 commit comments