@@ -418,21 +418,6 @@ private module SsaImpl {
418418 callEdge ( c1 , c2 ) and not intraInstanceCallEdge ( c1 , c2 )
419419 }
420420
421- /** Holds if a call to `x.c` can change the value of `x.f`. The actual update occurs in `setter`. */
422- private predicate setsOwnFieldTransitive ( Method c , Field f , Method setter ) {
423- setsOwnField ( setter , f ) and intraInstanceCallEdge * ( c , setter )
424- }
425-
426- /** Holds if a call to `c` can change the value of `f` on some instance. The actual update occurs in `setter`. */
427- private predicate generalSetter ( Callable c , Field f , Callable setter ) {
428- exists ( Method ownsetter |
429- setsOwnFieldTransitive ( ownsetter , f , setter ) and
430- crossInstanceCallEdge ( c , ownsetter )
431- )
432- or
433- setsOtherField ( c , f ) and c = setter
434- }
435-
436421 /**
437422 * Holds if `call` occurs in the same basic block, `b`, as `f` at index `i` and
438423 * `f` has an update somewhere.
@@ -487,78 +472,79 @@ private module SsaImpl {
487472 )
488473 }
489474
490- /**
491- * Holds if `c` is a relevant part of the call graph for
492- * `updatesNamedFieldPart1` based on following edges in forward direction.
493- */
494- private predicate pruneFromLeft ( Callable c ) {
495- exists ( Call call , SsaSourceField f |
496- generalSetter ( _, f .getField ( ) , _) and
497- relevantCall ( call , f ) and
498- c = tgt ( call )
499- )
500- or
501- exists ( Callable mid | pruneFromLeft ( mid ) and callEdge ( mid , c ) )
475+ private predicate source ( Call call , TrackedField f , Field field , Callable c , boolean fresh ) {
476+ relevantCall ( call , f ) and
477+ field = f .getField ( ) and
478+ c = tgt ( call ) and
479+ if c instanceof Constructor then fresh = true else fresh = false
502480 }
503481
504482 /**
505- * Holds if `c` is a relevant part of the call graph for
506- * `updatesNamedFieldPart1` based on following edges in backward direction.
483+ * A callable in a potential call-chain between a source that cares about the
484+ * value of some field `f` and a sink that may overwrite `f`. The boolean
485+ * `fresh` indicates whether the instance `this` in `c` has been freshly
486+ * allocated along the call-chain.
507487 */
508- private predicate pruneFromRight ( Callable c ) {
509- generalSetter ( c , _, _)
510- or
511- exists ( Callable mid | callEdge ( c , mid ) and pruneFromRight ( mid ) )
512- }
488+ private newtype TCallableNode =
489+ MkCallableNode ( Callable c , boolean fresh ) { source ( _, _, _, c , fresh ) or edge ( _, c , fresh ) }
513490
514- /** A restriction of the call graph to the parts that are relevant for `updatesNamedFieldPart1`. */
515- private class PrunedCallable extends Callable {
516- PrunedCallable ( ) { pruneFromLeft ( this ) and pruneFromRight ( this ) }
491+ private predicate edge ( TCallableNode n , Callable c2 , boolean f2 ) {
492+ exists ( Callable c1 , boolean f1 | n = MkCallableNode ( c1 , f1 ) |
493+ intraInstanceCallEdge ( c1 , c2 ) and f2 = f1
494+ or
495+ crossInstanceCallEdge ( c1 , c2 ) and
496+ if c2 instanceof Constructor then f2 = true else f2 = false
497+ )
517498 }
518499
519- private predicate callEdgePruned ( PrunedCallable c1 , PrunedCallable c2 ) { callEdge ( c1 , c2 ) }
520-
521- private predicate callEdgePlus ( PrunedCallable c1 , PrunedCallable c2 ) =
522- fastTC( callEdgePruned / 2 ) ( c1 , c2 )
500+ private predicate edge ( TCallableNode n1 , TCallableNode n2 ) {
501+ exists ( Callable c2 , boolean f2 |
502+ edge ( n1 , c2 , f2 ) and
503+ n2 = MkCallableNode ( c2 , f2 )
504+ )
505+ }
523506
524507 pragma [ noinline]
525- private predicate updatesNamedFieldPrefix ( Call call , TrackedField f , Callable c1 , Field field ) {
526- relevantCall ( call , f ) and
527- field = f .getField ( ) and
528- c1 = tgt ( call )
508+ private predicate source ( Call call , TrackedField f , Field field , TCallableNode n ) {
509+ exists ( Callable c , boolean fresh |
510+ source ( call , f , field , c , fresh ) and
511+ n = MkCallableNode ( c , fresh )
512+ )
529513 }
530514
531- pragma [ noinline]
532- private predicate generalSetterProj ( Callable c , Field f ) { generalSetter ( c , f , _) }
515+ private predicate sink ( Callable c , Field f , TCallableNode n ) {
516+ setsOwnField ( c , f ) and n = MkCallableNode ( c , false )
517+ or
518+ setsOtherField ( c , f ) and n = MkCallableNode ( c , _)
519+ }
533520
534- /**
535- * Holds if `call` may change the value of `f` on some instance, which may or
536- * may not alias with `this`. The actual update occurs in `setter`.
537- */
538- pragma [ noopt]
539- private predicate updatesNamedFieldPart1 ( Call call , TrackedField f , Callable setter ) {
540- exists ( Callable c1 , Callable c2 , Field field |
541- updatesNamedFieldPrefix ( call , f , c1 , field ) and
542- generalSetterProj ( c2 , field ) and
543- ( c1 = c2 or callEdgePlus ( c1 , c2 ) ) and
544- generalSetter ( c2 , field , setter )
545- )
521+ private predicate prunedNode ( TCallableNode n ) {
522+ sink ( _, _, n )
523+ or
524+ exists ( TCallableNode mid | edge ( n , mid ) and prunedNode ( mid ) )
546525 }
547526
548- /** Holds if `call` may change the value of `f` on `this`. The actual update occurs in `setter`. */
549- private predicate updatesNamedFieldPart2 ( Call call , TrackedField f , Callable setter ) {
550- relevantCall ( call , f ) and
551- setsOwnFieldTransitive ( tgt ( call ) , f . getField ( ) , setter )
527+ private predicate prunedEdge ( TCallableNode n1 , TCallableNode n2 ) {
528+ prunedNode ( n1 ) and
529+ prunedNode ( n2 ) and
530+ edge ( n1 , n2 )
552531 }
553532
533+ private predicate edgePlus ( TCallableNode c1 , TCallableNode c2 ) = fastTC( prunedEdge / 2 ) ( c1 , c2 )
534+
554535 /**
555536 * Holds if there exists a call-chain originating in `call` that can update `f` on some instance
556537 * where `f` and `call` share the same enclosing callable in which a
557538 * `FieldRead` of `f` is reachable from `call`.
558539 */
540+ pragma [ noopt]
559541 cached
560542 predicate updatesNamedField ( Call call , TrackedField f , Callable setter ) {
561- updatesNamedFieldPart1 ( call , f , setter ) or updatesNamedFieldPart2 ( call , f , setter )
543+ exists ( TCallableNode src , TCallableNode sink , Field field |
544+ source ( call , f , field , src ) and
545+ sink ( setter , field , sink ) and
546+ ( src = sink or edgePlus ( src , sink ) )
547+ )
562548 }
563549
564550 /** Holds if `n` might update the locally tracked variable `v`. */
@@ -806,6 +792,7 @@ private module SsaImpl {
806792 * Holds if `v` occurs at index `i1` in `b1` and at index `i2` in `b2` and
807793 * there is a path between them without any occurrence of `v`.
808794 */
795+ pragma [ nomagic]
809796 predicate adjacentVarRefs ( TrackedVar v , BasicBlock b1 , int i1 , BasicBlock b2 , int i2 ) {
810797 exists ( int rankix |
811798 b1 = b2 and
0 commit comments