Skip to content

Commit d429f90

Browse files
committed
Cache more things.
1 parent d5ec9c3 commit d429f90

File tree

1 file changed

+160
-150
lines changed
  • cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal

1 file changed

+160
-150
lines changed

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

Lines changed: 160 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import DataFlowUtil
66
private import DataFlowPrivate
77
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
88

9+
cached
910
private newtype TDefOrUse =
1011
TExplicitDef(Instruction store) { explicitWrite(_, store, _) } or
1112
TInitializeParam(Instruction instr) {
@@ -17,6 +18,7 @@ private newtype TDefOrUse =
1718
TReturnParamIndirection(Operand op) { returnParameterIndirection(op, _) }
1819

1920
pragma[nomagic]
21+
cached
2022
private int getRank(DefOrUse defOrUse, IRBlock block) {
2123
defOrUse =
2224
rank[result](int i, DefOrUse cand |
@@ -40,7 +42,6 @@ private class DefOrUse extends TDefOrUse {
4042
abstract IRBlock getBlock();
4143

4244
/** Holds if this definition or use has rank `rank` in block `block`. */
43-
cached
4445
predicate hasRankInBlock(IRBlock block, int rnk) {
4546
block = getBlock() and
4647
rnk = getRank(this, block)
@@ -206,20 +207,11 @@ predicate addressFlow(Instruction iFrom, Instruction iTo) {
206207
)
207208
}
208209

209-
private predicate valueFlow(Instruction iFrom, Instruction iTo) {
210-
iTo.(CopyValueInstruction).getSourceValue() = iFrom
211-
or
212-
iTo.(ConvertInstruction).getUnary() = iFrom
213-
or
214-
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
215-
or
216-
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
217-
}
218-
219210
/**
220211
* The reflexive, transitive closure of `addressFlow`. The boolean `readEffect` is `true` if any step in
221212
* the closure contains a step from the address of a `ReadSideEffectInstruction`.
222213
*/
214+
cached
223215
predicate addressFlowTC(Instruction iFrom, Instruction iTo) {
224216
iFrom = iTo and
225217
iTo = [getDestinationAddress(_), getSourceAddress(_)]
@@ -270,7 +262,7 @@ Operand getSourceAddressOperand(Instruction instr) {
270262
]
271263
}
272264

273-
predicate nodeLoadFromOperand(Node node, Operand operand) {
265+
private predicate nodeLoadFromOperand(Node node, Operand operand) {
274266
operand =
275267
[
276268
node.asInstruction().(LoadInstruction).getSourceAddressOperand(),
@@ -309,6 +301,7 @@ Operand getSourceValueOperand(Instruction instr) {
309301
* The addresses is computed using `address`, and `certain` is `true` if the write is guaranteed to overwrite
310302
* the entire variable.
311303
*/
304+
cached
312305
predicate explicitWrite(boolean certain, Instruction instr, Instruction address) {
313306
exists(StoreInstruction store |
314307
store = instr and addressFlowTC(address, store.getDestinationAddress())
@@ -325,145 +318,162 @@ predicate explicitWrite(boolean certain, Instruction instr, Instruction address)
325318
certain = false
326319
}
327320

328-
/**
329-
* Holds if `nodeFrom` is a read or write, and `nTo` is the next subsequent read of the variable
330-
* written (or read) by `storeOrRead`.
331-
*/
332321
cached
333-
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
334-
// Def-use/use-use flow from an `InstructionNode` to an `OperandNode`.
335-
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Use defOrUse, Use use, SourceVariable v |
336-
defOrUse.hasRankInBlock(bb1, i1) and
337-
use.hasRankInBlock(bb2, i2) and
338-
use.getVariable() = v and
339-
adjacentDefRead(_, bb1, i1, bb2, i2) and
340-
nodeFrom.asInstruction() = toInstruction(defOrUse) and
341-
flowOutOfAddressStep(use.getOperand(), nodeTo)
342-
)
343-
or
344-
// Use-use flow from a `ReadNode` to an `OperandNode`.
345-
exists(ReadNode read, IRBlock bb1, int i1, IRBlock bb2, int i2, Use use1, Use use2 |
346-
read = nodeFrom and
347-
use1.hasRankInBlock(bb1, i1) and
348-
use2.hasRankInBlock(bb2, i2) and
349-
use1.getOperand().getDef() = read.getInstruction() and
350-
adjacentDefRead(_, bb1, i1, bb2, i2) and
351-
flowOutOfAddressStep(use2.getOperand(), nodeTo)
352-
)
353-
or
354-
// Flow from phi nodes
355-
exists(PhiNode phi, Use use, IRBlock block, int rnk |
356-
phi = nodeFrom.(SsaPhiNode).getPhiNode() and
357-
use.hasRankInBlock(block, rnk) and
358-
phi.getSourceVariable() = use.getVariable() and
359-
flowOutOfAddressStep(use.getOperand(), nodeTo) and
360-
adjacentDefRead(_, phi.getBasicBlock(), -1, block, rnk)
361-
)
362-
or
363-
// Flow to phi nodes
364-
exists(Def def, StoreNode store, IRBlock block, int rnk |
365-
store = nodeFrom and
366-
store.isTerminal() and
367-
def.getInstruction() = store.getStoreInstruction() and
368-
def.hasRankInBlock(block, rnk) and
369-
nodeTo.(SsaPhiNode).hasInputAtRankInBlock(block, rnk)
370-
)
371-
or
372-
// Def-use flow from a `StoreNode` to an `OperandNode`.
373-
exists(
374-
StoreNode store, IRBlock bb1, int i1, IRBlock bb2, int i2, Def def, Use use, Definition ssaDef
375-
|
376-
store = nodeFrom and
377-
store.isTerminal() and
378-
def.getInstruction() = store.getStoreInstruction() and
379-
def.hasRankInBlock(bb1, i1) and
380-
adjacentDefRead(ssaDef, bb1, i1, bb2, i2) and
381-
use.hasRankInBlock(bb2, i2) and
382-
flowOutOfAddressStep(use.getOperand(), nodeTo)
383-
)
384-
or
385-
// This final case is a bit annoying. The write side effect on an expression like `a = new A;` writes
386-
// to a fresh address returned by `operator new`, and there's no easy way to use the shared SSA
387-
// library to hook that up to the assignment to `a`. So instead we flow to the _first_ use of the
388-
// value computed by `operator new` that occurs after `nodeFrom` (to avoid a loop in the
389-
// dataflow graph).
390-
exists(StoreNode store, WriteSideEffectInstruction write, IRBlock bb, int i1, int i2, Operand op |
391-
store = nodeFrom and
392-
store.getInstruction().(CallInstruction).getStaticCallTarget() instanceof
393-
Alloc::OperatorNewAllocationFunction and
394-
write = store.getStoreInstruction() and
395-
bb.getInstruction(i1) = write and
396-
bb.getInstruction(i2) = op.getUse() and
397-
// Flow to an instruction that occurs later in the block.
398-
valueFlow*(store.getInstruction(), op.getDef()) and
399-
nodeTo.asOperand() = op and
400-
i2 > i1 and
401-
// There is no previous instruction that also occurs after `nodeFrom`.
402-
not exists(Instruction instr, int i |
403-
bb.getInstruction(i) = instr and
404-
valueFlow(instr, op.getDef()) and
405-
i1 < i and
406-
i < i2
322+
private module Cached {
323+
/**
324+
* Holds if `nodeFrom` is a read or write, and `nTo` is the next subsequent read of the variable
325+
* written (or read) by `storeOrRead`.
326+
*/
327+
cached
328+
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
329+
// Def-use/use-use flow from an `InstructionNode` to an `OperandNode`.
330+
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Use defOrUse, Use use, SourceVariable v |
331+
defOrUse.hasRankInBlock(bb1, i1) and
332+
use.hasRankInBlock(bb2, i2) and
333+
use.getVariable() = v and
334+
adjacentDefRead(_, bb1, i1, bb2, i2) and
335+
nodeFrom.asInstruction() = toInstruction(defOrUse) and
336+
flowOutOfAddressStep(use.getOperand(), nodeTo)
407337
)
408-
)
409-
}
338+
or
339+
// Use-use flow from a `ReadNode` to an `OperandNode`.
340+
exists(ReadNode read, IRBlock bb1, int i1, IRBlock bb2, int i2, Use use1, Use use2 |
341+
read = nodeFrom and
342+
use1.hasRankInBlock(bb1, i1) and
343+
use2.hasRankInBlock(bb2, i2) and
344+
use1.getOperand().getDef() = read.getInstruction() and
345+
adjacentDefRead(_, bb1, i1, bb2, i2) and
346+
flowOutOfAddressStep(use2.getOperand(), nodeTo)
347+
)
348+
or
349+
// Flow from phi nodes
350+
exists(PhiNode phi, Use use, IRBlock block, int rnk |
351+
phi = nodeFrom.(SsaPhiNode).getPhiNode() and
352+
use.hasRankInBlock(block, rnk) and
353+
phi.getSourceVariable() = use.getVariable() and
354+
flowOutOfAddressStep(use.getOperand(), nodeTo) and
355+
adjacentDefRead(_, phi.getBasicBlock(), -1, block, rnk)
356+
)
357+
or
358+
// Flow to phi nodes
359+
exists(Def def, StoreNode store, IRBlock block, int rnk |
360+
store = nodeFrom and
361+
store.isTerminal() and
362+
def.getInstruction() = store.getStoreInstruction() and
363+
def.hasRankInBlock(block, rnk) and
364+
nodeTo.(SsaPhiNode).hasInputAtRankInBlock(block, rnk)
365+
)
366+
or
367+
// Def-use flow from a `StoreNode` to an `OperandNode`.
368+
exists(
369+
StoreNode store, IRBlock bb1, int i1, IRBlock bb2, int i2, Def def, Use use, Definition ssaDef
370+
|
371+
store = nodeFrom and
372+
store.isTerminal() and
373+
def.getInstruction() = store.getStoreInstruction() and
374+
def.hasRankInBlock(bb1, i1) and
375+
adjacentDefRead(ssaDef, bb1, i1, bb2, i2) and
376+
use.hasRankInBlock(bb2, i2) and
377+
flowOutOfAddressStep(use.getOperand(), nodeTo)
378+
)
379+
or
380+
// This final case is a bit annoying. The write side effect on an expression like `a = new A;` writes
381+
// to a fresh address returned by `operator new`, and there's no easy way to use the shared SSA
382+
// library to hook that up to the assignment to `a`. So instead we flow to the _first_ use of the
383+
// value computed by `operator new` that occurs after `nodeFrom` (to avoid a loop in the
384+
// dataflow graph).
385+
exists(
386+
StoreNode store, WriteSideEffectInstruction write, IRBlock bb, int i1, int i2, Operand op
387+
|
388+
store = nodeFrom and
389+
store.getInstruction().(CallInstruction).getStaticCallTarget() instanceof
390+
Alloc::OperatorNewAllocationFunction and
391+
write = store.getStoreInstruction() and
392+
bb.getInstruction(i1) = write and
393+
bb.getInstruction(i2) = op.getUse() and
394+
// Flow to an instruction that occurs later in the block.
395+
valueFlow*(store.getInstruction(), op.getDef()) and
396+
nodeTo.asOperand() = op and
397+
i2 > i1 and
398+
// There is no previous instruction that also occurs after `nodeFrom`.
399+
not exists(Instruction instr, int i |
400+
bb.getInstruction(i) = instr and
401+
valueFlow(instr, op.getDef()) and
402+
i1 < i and
403+
i < i2
404+
)
405+
)
406+
}
410407

411-
private predicate flowOutOfAddressStep(Operand operand, Node nTo) {
412-
// Flow into a read node
413-
exists(ReadNode readNode | readNode = nTo |
414-
not exists(readNode.getAPredecessor()) and
415-
operand.getDef() = readNode.getInstruction()
416-
)
417-
or
418-
exists(StoreNode storeNode | storeNode = nTo |
419-
not exists(storeNode.getAPredecessor()) and
420-
// Only transfer flow to a store node if it doesn't immediately overwrite the address
421-
// we've just written to.
422-
explicitWrite(false, storeNode.getStoreInstruction(), operand.getDef())
423-
)
424-
or
425-
nodeLoadFromOperand(nTo, operand)
426-
or
427-
exists(ReturnIndirectionInstruction ret |
428-
ret.getSourceAddressOperand() = operand and
429-
ret = nTo.asInstruction()
430-
)
431-
or
432-
exists(ReturnValueInstruction ret |
433-
ret.getReturnAddressOperand() = operand and
434-
nTo.asInstruction() = ret
435-
)
436-
or
437-
exists(CallInstruction call, int index, ReadSideEffectInstruction read |
438-
call.getArgumentOperand(index) = operand and
439-
read.getPrimaryInstruction() = call and
440-
read.getIndex() = index and
441-
nTo.asOperand() = read.getSideEffectOperand()
442-
)
443-
or
444-
exists(CopyInstruction copy |
445-
not exists(getSourceAddressOperand(copy)) and
446-
copy.getSourceValueOperand() = operand and
447-
flowOutOfAddressStep(copy.getAUse(), nTo)
448-
)
449-
or
450-
exists(ConvertInstruction convert |
451-
convert.getUnaryOperand() = operand and
452-
flowOutOfAddressStep(convert.getAUse(), nTo)
453-
)
454-
or
455-
exists(CheckedConvertOrNullInstruction convert |
456-
convert.getUnaryOperand() = operand and
457-
flowOutOfAddressStep(convert.getAUse(), nTo)
458-
)
459-
or
460-
exists(InheritanceConversionInstruction convert |
461-
convert.getUnaryOperand() = operand and
462-
flowOutOfAddressStep(convert.getAUse(), nTo)
463-
)
464-
or
465-
exists(PointerArithmeticInstruction arith |
466-
arith.getLeftOperand() = operand and
467-
flowOutOfAddressStep(arith.getAUse(), nTo)
468-
)
408+
private predicate flowOutOfAddressStep(Operand operand, Node nTo) {
409+
// Flow into a read node
410+
exists(ReadNode readNode | readNode = nTo |
411+
not exists(readNode.getAPredecessor()) and
412+
operand.getDef() = readNode.getInstruction()
413+
)
414+
or
415+
exists(StoreNode storeNode | storeNode = nTo |
416+
not exists(storeNode.getAPredecessor()) and
417+
// Only transfer flow to a store node if it doesn't immediately overwrite the address
418+
// we've just written to.
419+
explicitWrite(false, storeNode.getStoreInstruction(), operand.getDef())
420+
)
421+
or
422+
nodeLoadFromOperand(nTo, operand)
423+
or
424+
exists(ReturnIndirectionInstruction ret |
425+
ret.getSourceAddressOperand() = operand and
426+
ret = nTo.asInstruction()
427+
)
428+
or
429+
exists(ReturnValueInstruction ret |
430+
ret.getReturnAddressOperand() = operand and
431+
nTo.asInstruction() = ret
432+
)
433+
or
434+
exists(CallInstruction call, int index, ReadSideEffectInstruction read |
435+
call.getArgumentOperand(index) = operand and
436+
read.getPrimaryInstruction() = call and
437+
read.getIndex() = index and
438+
nTo.asOperand() = read.getSideEffectOperand()
439+
)
440+
or
441+
exists(CopyInstruction copy |
442+
not exists(getSourceAddressOperand(copy)) and
443+
copy.getSourceValueOperand() = operand and
444+
flowOutOfAddressStep(copy.getAUse(), nTo)
445+
)
446+
or
447+
exists(ConvertInstruction convert |
448+
convert.getUnaryOperand() = operand and
449+
flowOutOfAddressStep(convert.getAUse(), nTo)
450+
)
451+
or
452+
exists(CheckedConvertOrNullInstruction convert |
453+
convert.getUnaryOperand() = operand and
454+
flowOutOfAddressStep(convert.getAUse(), nTo)
455+
)
456+
or
457+
exists(InheritanceConversionInstruction convert |
458+
convert.getUnaryOperand() = operand and
459+
flowOutOfAddressStep(convert.getAUse(), nTo)
460+
)
461+
or
462+
exists(PointerArithmeticInstruction arith |
463+
arith.getLeftOperand() = operand and
464+
flowOutOfAddressStep(arith.getAUse(), nTo)
465+
)
466+
}
467+
468+
private predicate valueFlow(Instruction iFrom, Instruction iTo) {
469+
iTo.(CopyValueInstruction).getSourceValue() = iFrom
470+
or
471+
iTo.(ConvertInstruction).getUnary() = iFrom
472+
or
473+
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
474+
or
475+
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
476+
}
469477
}
478+
479+
import Cached

0 commit comments

Comments
 (0)