@@ -6,6 +6,7 @@ private import DataFlowUtil
6
6
private import DataFlowPrivate
7
7
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
8
8
9
+ cached
9
10
private newtype TDefOrUse =
10
11
TExplicitDef ( Instruction store ) { explicitWrite ( _, store , _) } or
11
12
TInitializeParam ( Instruction instr ) {
@@ -17,6 +18,7 @@ private newtype TDefOrUse =
17
18
TReturnParamIndirection ( Operand op ) { returnParameterIndirection ( op , _) }
18
19
19
20
pragma [ nomagic]
21
+ cached
20
22
private int getRank ( DefOrUse defOrUse , IRBlock block ) {
21
23
defOrUse =
22
24
rank [ result ] ( int i , DefOrUse cand |
@@ -40,7 +42,6 @@ private class DefOrUse extends TDefOrUse {
40
42
abstract IRBlock getBlock ( ) ;
41
43
42
44
/** Holds if this definition or use has rank `rank` in block `block`. */
43
- cached
44
45
predicate hasRankInBlock ( IRBlock block , int rnk ) {
45
46
block = getBlock ( ) and
46
47
rnk = getRank ( this , block )
@@ -206,20 +207,11 @@ predicate addressFlow(Instruction iFrom, Instruction iTo) {
206
207
)
207
208
}
208
209
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
-
219
210
/**
220
211
* The reflexive, transitive closure of `addressFlow`. The boolean `readEffect` is `true` if any step in
221
212
* the closure contains a step from the address of a `ReadSideEffectInstruction`.
222
213
*/
214
+ cached
223
215
predicate addressFlowTC ( Instruction iFrom , Instruction iTo ) {
224
216
iFrom = iTo and
225
217
iTo = [ getDestinationAddress ( _) , getSourceAddress ( _) ]
@@ -270,7 +262,7 @@ Operand getSourceAddressOperand(Instruction instr) {
270
262
]
271
263
}
272
264
273
- predicate nodeLoadFromOperand ( Node node , Operand operand ) {
265
+ private predicate nodeLoadFromOperand ( Node node , Operand operand ) {
274
266
operand =
275
267
[
276
268
node .asInstruction ( ) .( LoadInstruction ) .getSourceAddressOperand ( ) ,
@@ -309,6 +301,7 @@ Operand getSourceValueOperand(Instruction instr) {
309
301
* The addresses is computed using `address`, and `certain` is `true` if the write is guaranteed to overwrite
310
302
* the entire variable.
311
303
*/
304
+ cached
312
305
predicate explicitWrite ( boolean certain , Instruction instr , Instruction address ) {
313
306
exists ( StoreInstruction store |
314
307
store = instr and addressFlowTC ( address , store .getDestinationAddress ( ) )
@@ -325,145 +318,162 @@ predicate explicitWrite(boolean certain, Instruction instr, Instruction address)
325
318
certain = false
326
319
}
327
320
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
- */
332
321
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 )
407
337
)
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
+ }
410
407
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
+ }
469
477
}
478
+
479
+ import Cached
0 commit comments