@@ -132,62 +132,74 @@ private predicate sideEffectCfg(ControlFlow::Node src, ControlFlow::Node dst) {
132132private predicate iDomEffect ( ControlFlow:: Node dominator , ControlFlow:: Node node ) =
133133 idominance( entryNode / 1 , sideEffectCfg / 2 ) ( _, dominator , node )
134134
135- /**
136- * Gets the most recent side effect. To be more precise, `result` is a
137- * dominator of `node` and no side-effects can occur between `result` and
138- * `node`.
139- *
140- * `sideEffectCFG` has an edge from the function entry to every node with a
141- * side-effect. This means that every node with a side-effect has the
142- * function entry as its immediate dominator. So if node `x` dominates node
143- * `y` then there can be no side effects between `x` and `y` unless `x` is
144- * the function entry. So the optimal choice for `result` has the function
145- * entry as its immediate dominator.
146- *
147- * Example:
148- *
149- * ```
150- * 000: int f(int a, int b, int *p) {
151- * 001: int r = 0;
152- * 002: if (a) {
153- * 003: if (b) {
154- * 004: sideEffect1();
155- * 005: }
156- * 006: } else {
157- * 007: sideEffect2();
158- * 008: }
159- * 009: if (a) {
160- * 010: r++; // Not a side-effect, because r is an SSA variable.
161- * 011: }
162- * 012: if (b) {
163- * 013: r++; // Not a side-effect, because r is an SSA variable.
164- * 014: }
165- * 015: return *p;
166- * 016: }
167- * ```
168- *
169- * Suppose we want to find the most recent side-effect for the dereference
170- * of `p` on line 015. The `sideEffectCFG` has an edge from the function
171- * entry (line 000) to the side effects at lines 004 and 007. Therefore,
172- * the immediate dominator tree looks like this:
173- *
174- * 000 - 001 - 002 - 003
175- * - 004
176- * - 007
177- * - 009 - 010
178- * - 012 - 013
179- * - 015
180- *
181- * The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
182- * Therefore, the most recent side effect for line 015 is line 009.
183- */
184- cached
185- private ControlFlow:: Node mostRecentSideEffect ( ControlFlow:: Node node ) {
186- exists ( ControlFlow:: Node entry |
187- entryNode ( entry ) and
188- iDomEffect ( entry , result ) and
189- iDomEffect * ( result , node )
190- )
135+ private signature predicate relevantNodeSig ( ControlFlow:: Node n ) ;
136+
137+ private module MostRecentSideEffect< relevantNodeSig / 1 relevantNode> {
138+ private predicate iDomEntry ( ControlFlow:: Node node ) {
139+ exists ( ControlFlow:: Node entry |
140+ entryNode ( entry ) and
141+ iDomEffect ( entry , node )
142+ )
143+ }
144+
145+ private predicate iDomEffectPlus ( ControlFlow:: Node n1 , ControlFlow:: Node n2 ) =
146+ doublyBoundedFastTC( iDomEffect / 2 , iDomEntry / 1 , relevantNode / 1 ) ( n1 , n2 )
147+
148+ /**
149+ * Gets the most recent side effect. To be more precise, `result` is a
150+ * dominator of `node` and no side-effects can occur between `result` and
151+ * `node`.
152+ *
153+ * `sideEffectCFG` has an edge from the function entry to every node with a
154+ * side-effect. This means that every node with a side-effect has the
155+ * function entry as its immediate dominator. So if node `x` dominates node
156+ * `y` then there can be no side effects between `x` and `y` unless `x` is
157+ * the function entry. So the optimal choice for `result` has the function
158+ * entry as its immediate dominator.
159+ *
160+ * Example:
161+ *
162+ * ```
163+ * 000: int f(int a, int b, int *p) {
164+ * 001: int r = 0;
165+ * 002: if (a) {
166+ * 003: if (b) {
167+ * 004: sideEffect1();
168+ * 005: }
169+ * 006: } else {
170+ * 007: sideEffect2();
171+ * 008: }
172+ * 009: if (a) {
173+ * 010: r++; // Not a side-effect, because r is an SSA variable.
174+ * 011: }
175+ * 012: if (b) {
176+ * 013: r++; // Not a side-effect, because r is an SSA variable.
177+ * 014: }
178+ * 015: return *p;
179+ * 016: }
180+ * ```
181+ *
182+ * Suppose we want to find the most recent side-effect for the dereference
183+ * of `p` on line 015. The `sideEffectCFG` has an edge from the function
184+ * entry (line 000) to the side effects at lines 004 and 007. Therefore,
185+ * the immediate dominator tree looks like this:
186+ *
187+ * 000 - 001 - 002 - 003
188+ * - 004
189+ * - 007
190+ * - 009 - 010
191+ * - 012 - 013
192+ * - 015
193+ *
194+ * The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
195+ * Therefore, the most recent side effect for line 015 is line 009.
196+ */
197+ ControlFlow:: Node mostRecentSideEffect ( ControlFlow:: Node node ) {
198+ iDomEntry ( node ) and
199+ result = node
200+ or
201+ iDomEffectPlus ( node , result )
202+ }
191203}
192204
193205/** Used to represent the "global value number" of an expression. */
@@ -369,10 +381,12 @@ private predicate mkMethodAccess(DataFlow::Node access, GVN qualifier, Method m)
369381 )
370382}
371383
384+ private predicate isReadInstruction ( ControlFlow:: Node node ) { node instanceof IR:: ReadInstruction }
385+
372386private predicate analyzableFieldRead ( Read fread , DataFlow:: Node base , Field f ) {
373387 exists ( IR:: ReadInstruction r | r = fread .asInstruction ( ) |
374388 r .readsField ( base .asInstruction ( ) , f ) and
375- strictcount ( mostRecentSideEffect ( r ) ) = 1 and
389+ strictcount ( MostRecentSideEffect < isReadInstruction / 1 > :: mostRecentSideEffect ( r ) ) = 1 and
376390 not r .isConst ( )
377391 )
378392}
@@ -383,7 +397,8 @@ private predicate mkFieldRead(
383397 exists ( DataFlow:: Node base |
384398 analyzableFieldRead ( fread , base , v ) and
385399 qualifier = globalValueNumber ( base ) and
386- dominator = mostRecentSideEffect ( fread .asInstruction ( ) )
400+ dominator =
401+ MostRecentSideEffect< isReadInstruction / 1 > :: mostRecentSideEffect ( fread .asInstruction ( ) )
387402 )
388403}
389404
@@ -418,20 +433,23 @@ private predicate incompleteSsa(ValueEntity v) {
418433 )
419434}
420435
436+ private predicate instructionReads ( ControlFlow:: Node node ) { node .( IR:: Instruction ) .reads ( _) }
437+
421438/**
422439 * Holds if `access` is an access to a variable `target` for which SSA information is incomplete.
423440 */
424441private predicate analyzableOtherVariable ( DataFlow:: Node access , ValueEntity target ) {
425442 access .asInstruction ( ) .reads ( target ) and
426443 incompleteSsa ( target ) and
427- strictcount ( mostRecentSideEffect ( access .asInstruction ( ) ) ) = 1 and
444+ strictcount ( MostRecentSideEffect< instructionReads / 1 > :: mostRecentSideEffect ( access .asInstruction ( ) ) ) =
445+ 1 and
428446 not access .isConst ( ) and
429447 not target instanceof Function
430448}
431449
432450private predicate mkOtherVariable ( DataFlow:: Node access , ValueEntity x , ControlFlow:: Node dominator ) {
433451 analyzableOtherVariable ( access , x ) and
434- dominator = mostRecentSideEffect ( access .asInstruction ( ) )
452+ dominator = MostRecentSideEffect < instructionReads / 1 > :: mostRecentSideEffect ( access .asInstruction ( ) )
435453}
436454
437455private predicate analyzableBinaryOp (
@@ -463,8 +481,12 @@ private predicate mkUnaryOp(DataFlow::UnaryOperationNode op, GVN child, string o
463481 opname = op .getOperator ( )
464482}
465483
484+ private predicate isElementRead ( ControlFlow:: Node node ) {
485+ node instanceof IR:: ElementReadInstruction
486+ }
487+
466488private predicate analyzableIndexExpr ( DataFlow:: ElementReadNode ae ) {
467- strictcount ( mostRecentSideEffect ( ae .asInstruction ( ) ) ) = 1 and
489+ strictcount ( MostRecentSideEffect < isElementRead / 1 > :: mostRecentSideEffect ( ae .asInstruction ( ) ) ) = 1 and
468490 not ae .isConst ( )
469491}
470492
@@ -474,18 +496,25 @@ private predicate mkIndex(
474496 analyzableIndexExpr ( ae ) and
475497 base = globalValueNumber ( ae .getBase ( ) ) and
476498 offset = globalValueNumber ( ae .getIndex ( ) ) and
477- dominator = mostRecentSideEffect ( ae .asInstruction ( ) )
499+ dominator = MostRecentSideEffect< isElementRead / 1 > :: mostRecentSideEffect ( ae .asInstruction ( ) )
500+ }
501+
502+ private predicate isPointerDereference ( ControlFlow:: Node node ) {
503+ node instanceof IR:: EvalImplicitDerefInstruction
478504}
479505
480506private predicate analyzablePointerDereferenceExpr ( DataFlow:: PointerDereferenceNode deref ) {
481- strictcount ( mostRecentSideEffect ( deref .asInstruction ( ) ) ) = 1 and
507+ strictcount ( MostRecentSideEffect< isPointerDereference / 1 > :: mostRecentSideEffect ( deref
508+ .asInstruction ( ) )
509+ ) = 1 and
482510 not deref .isConst ( )
483511}
484512
485513private predicate mkDeref ( DataFlow:: PointerDereferenceNode deref , GVN p , ControlFlow:: Node dominator ) {
486514 analyzablePointerDereferenceExpr ( deref ) and
487515 p = globalValueNumber ( deref .getOperand ( ) ) and
488- dominator = mostRecentSideEffect ( deref .asInstruction ( ) )
516+ dominator =
517+ MostRecentSideEffect< isPointerDereference / 1 > :: mostRecentSideEffect ( deref .asInstruction ( ) )
489518}
490519
491520private predicate ssaInit ( SsaExplicitDefinition ssa , DataFlow:: Node rhs ) {
0 commit comments