@@ -13,44 +13,42 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313private import DataFlowPrivate
1414private import ModelUtil
1515private import SsaInternals as Ssa
16+ private import DataFlowImplCommon as DataFlowImplCommon
1617
18+ /**
19+ * The IR dataflow graph consists of the following nodes:
20+ * - `InstructionNode`, which injects most instructions directly into the dataflow graph.
21+ * - `OperandNode`, which similarly injects most operands directly into the dataflow graph.
22+ * - `VariableNode`, which is used to model flow through global variables.
23+ * - `PostFieldUpdateNode`, which is used to model the state of a field after a value has been stored
24+ * into an address after a number of loads.
25+ * - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library.
26+ * - `IndirectArgumentOutNode`, which represents the value of an argument (and its indirections) after
27+ * it leaves a function call.
28+ * - `RawIndirectOperand`, which represents the value of `operand` after loading the address a number
29+ * of times.
30+ * - `RawIndirectInstruction`, which represents the value of `instr` after loading the address a number
31+ * of times.
32+ */
1733cached
18- private module Cached {
19- /**
20- * The IR dataflow graph consists of the following nodes:
21- * - `InstructionNode`, which injects most instructions directly into the dataflow graph.
22- * - `OperandNode`, which similarly injects most operands directly into the dataflow graph.
23- * - `VariableNode`, which is used to model flow through global variables.
24- * - `PostFieldUpdateNode`, which is used to model the state of a field after a value has been stored
25- * into an address after a number of loads.
26- * - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library.
27- * - `IndirectArgumentOutNode`, which represents the value of an argument (and its indirections) after
28- * it leaves a function call.
29- * - `RawIndirectOperand`, which represents the value of `operand` after loading the address a number
30- * of times.
31- * - `RawIndirectInstruction`, which represents the value of `instr` after loading the address a number
32- * of times.
33- */
34- cached
35- newtype TIRDataFlowNode =
36- TNode0 ( Node0Impl node ) or
37- TVariableNode ( Variable var ) or
38- TPostFieldUpdateNode ( FieldAddress operand , int indirectionIndex ) {
39- indirectionIndex =
40- [ 1 .. Ssa:: countIndirectionsForCppType ( operand .getObjectAddress ( ) .getResultLanguageType ( ) ) ]
41- } or
42- TSsaPhiNode ( Ssa:: PhiNode phi ) or
43- TIndirectArgumentOutNode ( ArgumentOperand operand , int indirectionIndex ) {
44- Ssa:: isModifiableByCall ( operand ) and
45- indirectionIndex = [ 1 .. Ssa:: countIndirectionsForCppType ( operand .getLanguageType ( ) ) ]
46- } or
47- TRawIndirectOperand ( Operand op , int indirectionIndex ) {
48- Ssa:: hasRawIndirectOperand ( op , indirectionIndex )
49- } or
50- TRawIndirectInstruction ( Instruction instr , int indirectionIndex ) {
51- Ssa:: hasRawIndirectInstruction ( instr , indirectionIndex )
52- }
53- }
34+ newtype TIRDataFlowNode =
35+ TNode0 ( Node0Impl node ) { DataFlowImplCommon:: forceCachingInSameStage ( ) } or
36+ TVariableNode ( Variable var ) or
37+ TPostFieldUpdateNode ( FieldAddress operand , int indirectionIndex ) {
38+ indirectionIndex =
39+ [ 1 .. Ssa:: countIndirectionsForCppType ( operand .getObjectAddress ( ) .getResultLanguageType ( ) ) ]
40+ } or
41+ TSsaPhiNode ( Ssa:: PhiNode phi ) or
42+ TIndirectArgumentOutNode ( ArgumentOperand operand , int indirectionIndex ) {
43+ Ssa:: isModifiableByCall ( operand ) and
44+ indirectionIndex = [ 1 .. Ssa:: countIndirectionsForCppType ( operand .getLanguageType ( ) ) ]
45+ } or
46+ TRawIndirectOperand ( Operand op , int indirectionIndex ) {
47+ Ssa:: hasRawIndirectOperand ( op , indirectionIndex )
48+ } or
49+ TRawIndirectInstruction ( Instruction instr , int indirectionIndex ) {
50+ Ssa:: hasRawIndirectInstruction ( instr , indirectionIndex )
51+ }
5452
5553/**
5654 * An operand that is defined by a `FieldAddressInstruction`.
@@ -94,8 +92,6 @@ predicate conversionFlow(Operand opFrom, Instruction instrTo, boolean isPointerA
9492 instrTo .( PointerArithmeticInstruction ) .getLeftOperand ( ) = opFrom
9593}
9694
97- private import Cached
98-
9995/**
10096 * A node in a data flow graph.
10197 *
@@ -1180,36 +1176,6 @@ VariableNode variableNode(Variable v) { result.getVariable() = v }
11801176 */
11811177Node uninitializedNode ( LocalVariable v ) { none ( ) }
11821178
1183- /**
1184- * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
1185- * (intra-procedural) step.
1186- */
1187- predicate localFlowStep = simpleLocalFlowStep / 2 ;
1188-
1189- private predicate indirectionOperandFlow ( RawIndirectOperand nodeFrom , Node nodeTo ) {
1190- // Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
1191- exists ( int ind , Instruction load , Operand address |
1192- Ssa:: isDereference ( load , address ) and
1193- hasOperandAndIndex ( nodeFrom , address , ind ) and
1194- nodeHasInstruction ( nodeTo , load , ind - 1 )
1195- )
1196- or
1197- // If an operand flows to an instruction, then the indirection of
1198- // the operand also flows to the indirction of the instruction.
1199- exists ( Operand operand , Instruction instr , int indirectionIndex |
1200- simpleInstructionLocalFlowStep ( operand , instr ) and
1201- hasOperandAndIndex ( nodeFrom , operand , indirectionIndex ) and
1202- hasInstructionAndIndex ( nodeTo , instr , indirectionIndex )
1203- )
1204- or
1205- // If there's indirect flow to an operand, then there's also indirect
1206- // flow to the operand after applying some pointer arithmetic.
1207- exists ( PointerArithmeticInstruction pointerArith , int indirectionIndex |
1208- hasOperandAndIndex ( nodeFrom , pointerArith .getAnOperand ( ) , indirectionIndex ) and
1209- hasInstructionAndIndex ( nodeTo , pointerArith , indirectionIndex )
1210- )
1211- }
1212-
12131179pragma [ noinline]
12141180predicate hasOperandAndIndex ( IndirectOperand indirectOperand , Operand operand , int indirectionIndex ) {
12151181 indirectOperand .getOperand ( ) = operand and
@@ -1224,92 +1190,130 @@ predicate hasInstructionAndIndex(
12241190 indirectInstr .getIndirectionIndex ( ) = indirectionIndex
12251191}
12261192
1227- private predicate indirectionInstructionFlow ( RawIndirectInstruction nodeFrom , IndirectOperand nodeTo ) {
1228- // If there's flow from an instruction to an operand, then there's also flow from the
1229- // indirect instruction to the indirect operand.
1230- exists ( Operand operand , Instruction instr , int indirectionIndex |
1231- simpleOperandLocalFlowStep ( pragma [ only_bind_into ] ( instr ) , pragma [ only_bind_into ] ( operand ) )
1232- |
1233- hasOperandAndIndex ( nodeTo , operand , indirectionIndex ) and
1234- hasInstructionAndIndex ( nodeFrom , instr , indirectionIndex )
1235- )
1236- }
1193+ cached
1194+ private module Cached {
1195+ /**
1196+ * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
1197+ * (intra-procedural) step.
1198+ */
1199+ cached
1200+ predicate localFlowStep ( Node nodeFrom , Node nodeTo ) { simpleLocalFlowStep ( nodeFrom , nodeTo ) }
12371201
1238- /**
1239- * INTERNAL: do not use.
1240- *
1241- * This is the local flow predicate that's used as a building block in global
1242- * data flow. It may have less flow than the `localFlowStep` predicate.
1243- */
1244- predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
1245- // Post update node -> Node flow
1246- Ssa:: ssaFlow ( nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
1247- or
1248- // Def-use/Use-use flow
1249- Ssa:: ssaFlow ( nodeFrom , nodeTo )
1250- or
1251- // Operand -> Instruction flow
1252- simpleInstructionLocalFlowStep ( nodeFrom .asOperand ( ) , nodeTo .asInstruction ( ) )
1253- or
1254- // Instruction -> Operand flow
1255- simpleOperandLocalFlowStep ( nodeFrom .asInstruction ( ) , nodeTo .asOperand ( ) )
1256- or
1257- // Phi node -> Node flow
1258- Ssa:: fromPhiNode ( nodeFrom , nodeTo )
1259- or
1260- // Indirect operand -> (indirect) instruction flow
1261- indirectionOperandFlow ( nodeFrom , nodeTo )
1262- or
1263- // Indirect instruction -> indirect operand flow
1264- indirectionInstructionFlow ( nodeFrom , nodeTo )
1265- or
1266- // Flow through modeled functions
1267- modelFlow ( nodeFrom , nodeTo )
1268- or
1269- // Reverse flow: data that flows from the definition node back into the indirection returned
1270- // by a function. This allows data to flow 'in' through references returned by a modeled
1271- // function such as `operator[]`.
1272- exists ( Operand address , int indirectionIndex |
1273- nodeHasOperand ( nodeTo .( IndirectReturnOutNode ) , address , indirectionIndex )
1274- |
1275- exists ( StoreInstruction store |
1276- nodeHasInstruction ( nodeFrom , store , indirectionIndex - 1 ) and
1277- store .getDestinationAddressOperand ( ) = address
1202+ private predicate indirectionOperandFlow ( RawIndirectOperand nodeFrom , Node nodeTo ) {
1203+ // Reduce the indirection count by 1 if we're passing through a `LoadInstruction`.
1204+ exists ( int ind , LoadInstruction load |
1205+ hasOperandAndIndex ( nodeFrom , load .getSourceAddressOperand ( ) , ind ) and
1206+ nodeHasInstruction ( nodeTo , load , ind - 1 )
12781207 )
12791208 or
1280- Ssa:: outNodeHasAddressAndIndex ( nodeFrom , address , indirectionIndex )
1281- )
1282- }
1209+ // If an operand flows to an instruction, then the indirection of
1210+ // the operand also flows to the indirction of the instruction.
1211+ exists ( Operand operand , Instruction instr , int indirectionIndex |
1212+ simpleInstructionLocalFlowStep ( operand , instr ) and
1213+ hasOperandAndIndex ( nodeFrom , operand , indirectionIndex ) and
1214+ hasInstructionAndIndex ( nodeTo , instr , indirectionIndex )
1215+ )
1216+ or
1217+ // If there's indirect flow to an operand, then there's also indirect
1218+ // flow to the operand after applying some pointer arithmetic.
1219+ exists ( PointerArithmeticInstruction pointerArith , int indirectionIndex |
1220+ hasOperandAndIndex ( nodeFrom , pointerArith .getAnOperand ( ) , indirectionIndex ) and
1221+ hasInstructionAndIndex ( nodeTo , pointerArith , indirectionIndex )
1222+ )
1223+ }
12831224
1284- private predicate simpleInstructionLocalFlowStep ( Operand opFrom , Instruction iTo ) {
1285- // Treat all conversions as flow, even conversions between different numeric types.
1286- conversionFlow ( opFrom , iTo , false )
1287- or
1288- iTo .( CopyInstruction ) .getSourceValueOperand ( ) = opFrom
1289- }
1225+ private predicate indirectionInstructionFlow (
1226+ RawIndirectInstruction nodeFrom , IndirectOperand nodeTo
1227+ ) {
1228+ // If there's flow from an instruction to an operand, then there's also flow from the
1229+ // indirect instruction to the indirect operand.
1230+ exists ( Operand operand , Instruction instr , int indirectionIndex |
1231+ simpleOperandLocalFlowStep ( pragma [ only_bind_into ] ( instr ) , pragma [ only_bind_into ] ( operand ) )
1232+ |
1233+ hasOperandAndIndex ( nodeTo , operand , indirectionIndex ) and
1234+ hasInstructionAndIndex ( nodeFrom , instr , indirectionIndex )
1235+ )
1236+ }
12901237
1291- private predicate simpleOperandLocalFlowStep ( Instruction iFrom , Operand opTo ) {
1292- not opTo instanceof MemoryOperand and
1293- opTo .getDef ( ) = iFrom
1294- }
1238+ /**
1239+ * INTERNAL: do not use.
1240+ *
1241+ * This is the local flow predicate that's used as a building block in global
1242+ * data flow. It may have less flow than the `localFlowStep` predicate.
1243+ */
1244+ cached
1245+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
1246+ // Post update node -> Node flow
1247+ Ssa:: ssaFlow ( nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
1248+ or
1249+ // Def-use/Use-use flow
1250+ Ssa:: ssaFlow ( nodeFrom , nodeTo )
1251+ or
1252+ // Operand -> Instruction flow
1253+ simpleInstructionLocalFlowStep ( nodeFrom .asOperand ( ) , nodeTo .asInstruction ( ) )
1254+ or
1255+ // Instruction -> Operand flow
1256+ simpleOperandLocalFlowStep ( nodeFrom .asInstruction ( ) , nodeTo .asOperand ( ) )
1257+ or
1258+ // Phi node -> Node flow
1259+ Ssa:: fromPhiNode ( nodeFrom , nodeTo )
1260+ or
1261+ // Indirect operand -> (indirect) instruction flow
1262+ indirectionOperandFlow ( nodeFrom , nodeTo )
1263+ or
1264+ // Indirect instruction -> indirect operand flow
1265+ indirectionInstructionFlow ( nodeFrom , nodeTo )
1266+ or
1267+ // Flow through modeled functions
1268+ modelFlow ( nodeFrom , nodeTo )
1269+ or
1270+ // Reverse flow: data that flows from the definition node back into the indirection returned
1271+ // by a function. This allows data to flow 'in' through references returned by a modeled
1272+ // function such as `operator[]`.
1273+ exists ( Operand address , int indirectionIndex |
1274+ nodeHasOperand ( nodeTo .( IndirectReturnOutNode ) , address , indirectionIndex )
1275+ |
1276+ exists ( StoreInstruction store |
1277+ nodeHasInstruction ( nodeFrom , store , indirectionIndex - 1 ) and
1278+ store .getDestinationAddressOperand ( ) = address
1279+ )
1280+ or
1281+ Ssa:: outNodeHasAddressAndIndex ( nodeFrom , address , indirectionIndex )
1282+ )
1283+ }
12951284
1296- private predicate modelFlow ( Node nodeFrom , Node nodeTo ) {
1297- exists (
1298- CallInstruction call , DataFlowFunction func , FunctionInput modelIn , FunctionOutput modelOut
1299- |
1300- call .getStaticCallTarget ( ) = func and
1301- func .hasDataFlow ( modelIn , modelOut )
1302- |
1303- nodeFrom = callInput ( call , modelIn ) and
1304- nodeTo = callOutput ( call , modelOut )
1285+ private predicate simpleInstructionLocalFlowStep ( Operand opFrom , Instruction iTo ) {
1286+ // Treat all conversions as flow, even conversions between different numeric types.
1287+ conversionFlow ( opFrom , iTo , false )
13051288 or
1306- exists ( int d |
1307- nodeFrom = callInput ( call , modelIn , d ) and
1308- nodeTo = callOutput ( call , modelOut , d )
1289+ iTo .( CopyInstruction ) .getSourceValueOperand ( ) = opFrom
1290+ }
1291+
1292+ private predicate simpleOperandLocalFlowStep ( Instruction iFrom , Operand opTo ) {
1293+ not opTo instanceof MemoryOperand and
1294+ opTo .getDef ( ) = iFrom
1295+ }
1296+
1297+ private predicate modelFlow ( Node nodeFrom , Node nodeTo ) {
1298+ exists (
1299+ CallInstruction call , DataFlowFunction func , FunctionInput modelIn , FunctionOutput modelOut
1300+ |
1301+ call .getStaticCallTarget ( ) = func and
1302+ func .hasDataFlow ( modelIn , modelOut )
1303+ |
1304+ nodeFrom = callInput ( call , modelIn ) and
1305+ nodeTo = callOutput ( call , modelOut )
1306+ or
1307+ exists ( int d |
1308+ nodeFrom = callInput ( call , modelIn , d ) and
1309+ nodeTo = callOutput ( call , modelOut , d )
1310+ )
13091311 )
1310- )
1312+ }
13111313}
13121314
1315+ import Cached
1316+
13131317/**
13141318 * Holds if data flows from `source` to `sink` in zero or more local
13151319 * (intra-procedural) steps.
0 commit comments