Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit de70cbf

Browse files
committed
C++: Change caching for dataflow.
1 parent 2ad61df commit de70cbf

1 file changed

Lines changed: 148 additions & 144 deletions

File tree

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

Lines changed: 148 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,42 @@ private import semmle.code.cpp.models.interfaces.DataFlow
1313
private import DataFlowPrivate
1414
private import ModelUtil
1515
private 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+
*/
1733
cached
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
*/
11811177
Node 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-
12131179
pragma[noinline]
12141180
predicate 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

Comments
 (0)