@@ -128,6 +128,8 @@ private module Cached {
128128 n = member .getBase ( ) and
129129 not member .isStatic ( )
130130 )
131+ or
132+ n = any ( CfgNodes:: ExprNodes:: IndexCfgNode index ) .getBase ( )
131133 }
132134
133135 cached
@@ -219,23 +221,51 @@ private module Cached {
219221 }
220222
221223 cached
222- newtype TContentSet = TSingletonContent ( Content c )
224+ newtype TContentSet =
225+ TSingletonContent ( Content c ) or
226+ TAnyElementContent ( ) or
227+ TKnownOrUnknownElementContent ( Content:: KnownElementContent c )
228+
229+ private predicate trackKnownValue ( ConstantValue cv ) {
230+ exists ( cv .asString ( ) )
231+ or
232+ cv .asInt ( ) = [ 0 .. 10 ]
233+ }
223234
224235 cached
225236 newtype TContent =
226237 TFieldContent ( string name ) {
227238 name = any ( PropertyMember member ) .getName ( )
228239 or
229240 name = any ( MemberExpr me ) .getMemberName ( )
230- }
241+ } or
242+ TKnownElementContent ( ConstantValue cv ) { trackKnownValue ( cv ) } or
243+ TUnknownElementContent ( )
231244
232245 cached
233- newtype TContentApprox = TNonElementContentApprox ( Content c )
246+ newtype TContentApprox =
247+ TNonElementContentApprox ( Content c ) { not c instanceof Content:: ElementContent } or
248+ TUnknownElementContentApprox ( ) or
249+ TKnownIntegerElementContentApprox ( ) or
250+ TKnownElementContentApprox ( string approx ) { approx = approxKnownElementIndex ( _) }
234251
235252 cached
236253 newtype TDataFlowType = TUnknownDataFlowType ( )
237254}
238255
256+ class TElementContent = TKnownElementContent or TUnknownElementContent ;
257+
258+ /** Gets a string for approximating known element indices. */
259+ private string approxKnownElementIndex ( ConstantValue cv ) {
260+ not exists ( cv .asInt ( ) ) and
261+ exists ( string s | s = cv .serialize ( ) |
262+ s .length ( ) < 2 and
263+ result = s
264+ or
265+ result = s .prefix ( 2 )
266+ )
267+ }
268+
239269import Cached
240270
241271/** Holds if `n` should be hidden from path explanations. */
@@ -477,26 +507,54 @@ predicate jumpStep(Node pred, Node succ) {
477507 * content `c`.
478508 */
479509predicate storeStep ( Node node1 , ContentSet c , Node node2 ) {
480- node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) =
481- any ( CfgNodes:: ExprNodes:: MemberCfgNode var |
482- exists ( CfgNodes:: StmtNodes:: AssignStmtCfgNode assign |
483- var = assign .getLeftHandSide ( ) and
484- node1 .asStmt ( ) = assign .getRightHandSide ( )
485- |
486- c .isSingleton ( any ( Content:: FieldContent ct | ct .getName ( ) = var .getMemberName ( ) ) )
487- )
488- ) .getBase ( )
510+ exists ( CfgNodes:: ExprNodes:: MemberCfgWriteAccessNode var , Content:: FieldContent fc |
511+ node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = var .getBase ( ) and
512+ node1 .asStmt ( ) = var .getAssignStmt ( ) .getRightHandSide ( ) and
513+ fc .getName ( ) = var .getMemberName ( ) and
514+ c .isSingleton ( fc )
515+ )
516+ or
517+ exists (
518+ CfgNodes:: ExprNodes:: IndexCfgWriteNode var , Content:: KnownElementContent ec , int index ,
519+ CfgNodes:: ExprCfgNode e
520+ |
521+ node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) = var .getBase ( ) and
522+ node1 .asStmt ( ) = var .getAssignStmt ( ) .getRightHandSide ( ) and
523+ c .isKnownOrUnknownElement ( ec ) and
524+ index = ec .getIndex ( ) .asInt ( ) and
525+ e = var .getIndex ( )
526+ |
527+ index = e .getValue ( ) .asInt ( )
528+ or
529+ not exists ( e .getValue ( ) .asInt ( ) )
530+ )
489531}
490532
491533/**
492534 * Holds if there is a read step of content `c` from `node1` to `node2`.
493535 */
494536predicate readStep ( Node node1 , ContentSet c , Node node2 ) {
495- node2 .asExpr ( ) =
496- any ( CfgNodes:: ExprNodes:: MemberCfgReadAccessNode var |
497- node1 .asExpr ( ) = var .getBase ( ) and
498- c .isSingleton ( any ( Content:: FieldContent ct | ct .getName ( ) = var .getMemberName ( ) ) )
499- )
537+ exists ( CfgNodes:: ExprNodes:: MemberCfgReadAccessNode var , Content:: FieldContent fc |
538+ node2 .asExpr ( ) = var and
539+ node1 .asExpr ( ) = var .getBase ( ) and
540+ fc .getName ( ) = var .getMemberName ( ) and
541+ c .isSingleton ( fc )
542+ )
543+ or
544+ exists (
545+ CfgNodes:: ExprNodes:: IndexCfgReadNode var , Content:: KnownElementContent ec , int index ,
546+ CfgNodes:: ExprCfgNode e
547+ |
548+ node2 .asExpr ( ) = var and
549+ node1 .asExpr ( ) = var .getBase ( ) and
550+ c .isKnownOrUnknownElement ( ec ) and
551+ index = ec .getIndex ( ) .asInt ( ) and
552+ e = var .getIndex ( )
553+ |
554+ index = e .getValue ( ) .asInt ( )
555+ or
556+ not exists ( e .getValue ( ) .asInt ( ) )
557+ )
500558}
501559
502560/**
@@ -584,7 +642,7 @@ class DataFlowExpr = CfgNodes::ExprCfgNode;
584642 * Holds if access paths with `c` at their head always should be tracked at high
585643 * precision. This disables adaptive access path precision for such access paths.
586644 */
587- predicate forceHighPrecision ( Content c ) { none ( ) }
645+ predicate forceHighPrecision ( Content c ) { c instanceof Content :: ElementContent }
588646
589647class NodeRegion instanceof Unit {
590648 string toString ( ) { result = "NodeRegion" }
@@ -653,7 +711,18 @@ class ContentApprox extends TContentApprox {
653711}
654712
655713/** Gets an approximated value for content `c`. */
656- ContentApprox getContentApprox ( Content c ) { result = TNonElementContentApprox ( c ) }
714+ ContentApprox getContentApprox ( Content c ) {
715+ c instanceof Content:: UnknownElementContent and
716+ result = TUnknownElementContentApprox ( )
717+ or
718+ exists ( c .( Content:: KnownElementContent ) .getIndex ( ) .asInt ( ) ) and
719+ result = TKnownIntegerElementContentApprox ( )
720+ or
721+ result =
722+ TKnownElementContentApprox ( approxKnownElementIndex ( c .( Content:: KnownElementContent ) .getIndex ( ) ) )
723+ or
724+ result = TNonElementContentApprox ( c )
725+ }
657726
658727/**
659728 * A unit class for adding additional jump steps.
0 commit comments