diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index c6bdcc206b45..4dbae11ddedb 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -375,6 +375,8 @@ module MakeImpl Lang> { class ApNil extends Ap; + predicate apTracksLength(); + bindingset[result, ap] ApApprox getApprox(Ap ap); @@ -563,6 +565,7 @@ module MakeImpl Lang> { pragma[nomagic] private int getAnApLengthLowerBound(Ap ap) { + not apTracksLength() and // no need if we are tracking precise length information accessPathLimit() > 1 and // `accessPathLimit() <= 1` is already checked in stages 1 and 2 ap instanceof ApNil and result = 0 @@ -609,7 +612,7 @@ module MakeImpl Lang> { fwdFlowStore(_, _, ap0, _, c, t, stored, node, cc, summaryCtx) and ap = apCons(c, ap0) and apa = getApprox(ap) and - if accessPathLimit() > 1 + if accessPathLimit() > 1 and not apTracksLength() then getAnApLengthLowerBound(ap0) < accessPathLimit() else any() ) @@ -1339,6 +1342,7 @@ module MakeImpl Lang> { pragma[nomagic] private int getAnApLengthLowerBoundRev(Ap ap) { + not apTracksLength() and // no need if we are tracking precise length information accessPathLimit() > 1 and // `accessPathLimit() <= 1` is already checked in stages 1 and 2 ap instanceof ApNil and result = 0 @@ -1388,7 +1392,7 @@ module MakeImpl Lang> { exists(Nd mid, Ap ap0 | revFlow(mid, returnCtx, returnAp, ap0) and readStepFwd(node, ap, _, mid, ap0) and - if accessPathLimit() > 1 + if accessPathLimit() > 1 and not apTracksLength() then getAnApLengthLowerBoundRev(ap0) < accessPathLimit() else any() ) @@ -2776,6 +2780,8 @@ module MakeImpl Lang> { ApNil() { this = false } } + predicate apTracksLength() { none() } + bindingset[result, ap] PrevStage::Ap getApprox(Ap ap) { any() } @@ -2854,17 +2860,26 @@ module MakeImpl Lang> { class ApNil = ApproxAccessPathFrontNil; + predicate apTracksLength() { any() } + PrevStage::Ap getApprox(Ap ap) { result = ap.toBoolNonEmpty() } Typ getTyp(Type t) { any() } bindingset[c, tail] - Ap apCons(Content c, Ap tail) { result.getAHead() = c and exists(tail) } + Ap apCons(Content c, Ap tail) { + exists(int length | result.getAHead(length) = c | + length = 1 and + tail instanceof ApNil + or + tail = TApproxFrontHead(_, length - 1) + ) + } class ApHeadContent = ContentApprox; pragma[noinline] - ApHeadContent getHeadContent(Ap ap) { result = ap.getHead() } + ApHeadContent getHeadContent(Ap ap) { result = ap.getHead(_) } predicate projectToHeadContent = getContentApproxCached/1; @@ -2910,7 +2925,7 @@ module MakeImpl Lang> { PrevStage::revFlow(node) and PrevStage::readStepCand(_, c, _) and Stage1::expectsContentEx(node, c) and - c = ap.getAHead() + c = ap.getAHead(_) ) } @@ -2956,17 +2971,26 @@ module MakeImpl Lang> { class ApNil = AccessPathFrontNil; + predicate apTracksLength() { any() } + PrevStage::Ap getApprox(Ap ap) { result = ap.toApprox() } Typ getTyp(Type t) { any() } bindingset[c, tail] - Ap apCons(Content c, Ap tail) { result.getHead() = c and exists(tail) } + Ap apCons(Content c, Ap tail) { + exists(int length | result.getHead(length) = c | + length = 1 and + tail instanceof ApNil + or + tail = TFrontHead(_, length - 1) + ) + } class ApHeadContent = Content; pragma[noinline] - ApHeadContent getHeadContent(Ap ap) { result = ap.getHead() } + ApHeadContent getHeadContent(Ap ap) { result = ap.getHead(_) } ApHeadContent projectToHeadContent(Content c) { result = c } @@ -3012,11 +3036,11 @@ module MakeImpl Lang> { // When `node` is the target of a store, we interpret `clearsContent` as // only pertaining to _earlier_ store steps. In this case, we need to postpone // checking `clearsContent` to the step creation. - clearContent(node, ap.getHead(), false) + clearContent(node, ap.getHead(_), false) } pragma[nomagic] - private predicate clearExceptStore(Nd node, Ap ap) { clearContent(node, ap.getHead(), true) } + private predicate clearExceptStore(Nd node, Ap ap) { clearContent(node, ap.getHead(_), true) } pragma[nomagic] private predicate expectsContentCand(Nd node, Ap ap) { @@ -3024,7 +3048,7 @@ module MakeImpl Lang> { PrevStage::revFlow(node) and PrevStage::readStepCand(_, c, _) and Stage1::expectsContentEx(node, c) and - c = ap.getHead() + c = ap.getHead(_) ) } @@ -3059,9 +3083,9 @@ module MakeImpl Lang> { tails = strictcount(AccessPathFront apf | Stage4::consCand(c, apf)) and nodes = strictcount(Nd n | - Stage4::revFlow(n, any(AccessPathFrontHead apf | apf.getHead() = c)) + Stage4::revFlow(n, any(AccessPathFrontHead apf | apf.getHead(_) = c)) or - Stage4::nodeMayUseSummary(n, any(AccessPathFrontHead apf | apf.getHead() = c)) + Stage4::nodeMayUseSummary(n, any(AccessPathFrontHead apf | apf.getHead(_) = c)) ) and accessPathApproxCostLimits(apLimit, tupleLimit) and apLimit < tails and @@ -3077,7 +3101,7 @@ module MakeImpl Lang> { not expensiveLen2unfolding(c) } or TConsCons(Content c1, Content c2, int len) { - Stage4::consCand(c1, TFrontHead(c2)) and + Stage4::consCand(c1, TFrontHead(c2, _)) and len in [2 .. Config::accessPathLimit()] and not expensiveLen2unfolding(c1) } or @@ -3131,7 +3155,7 @@ module MakeImpl Lang> { override int len() { result = 1 } - override AccessPathFront getFront() { result = TFrontHead(c) } + override AccessPathFront getFront() { result = TFrontHead(c, 1) } override predicate isCons(Content head, AccessPathApprox tail) { head = c and tail = TNil() } } @@ -3153,7 +3177,7 @@ module MakeImpl Lang> { override int len() { result = len } - override AccessPathFront getFront() { result = TFrontHead(c1) } + override AccessPathFront getFront() { result = TFrontHead(c1, len) } override predicate isCons(Content head, AccessPathApprox tail) { head = c1 and @@ -3184,12 +3208,12 @@ module MakeImpl Lang> { override int len() { result = len } - override AccessPathFront getFront() { result = TFrontHead(c) } + override AccessPathFront getFront() { result = TFrontHead(c, len) } override predicate isCons(Content head, AccessPathApprox tail) { head = c and ( - exists(Content c2 | Stage4::consCand(c, TFrontHead(c2)) | + exists(Content c2 | Stage4::consCand(c, TFrontHead(c2, len - 1)) | tail = TConsCons(c2, _, len - 1) or len = 2 and @@ -3226,6 +3250,8 @@ module MakeImpl Lang> { class ApNil = AccessPathApproxNil; + predicate apTracksLength() { any() } + pragma[nomagic] PrevStage::Ap getApprox(Ap ap) { result = ap.getFront() } @@ -3416,6 +3442,8 @@ module MakeImpl Lang> { class ApNil = AccessPathNil; + predicate apTracksLength() { any() } + pragma[nomagic] PrevStage::Ap getApprox(Ap ap) { result = ap.getApprox() } @@ -3531,7 +3559,7 @@ module MakeImpl Lang> { override predicate isCons(Content head, AccessPath tail) { head = head_ and tail = tail_ } - override AccessPathFrontHead getFront() { result = TFrontHead(head_) } + override AccessPathFrontHead getFront() { result = TFrontHead(head_, this.length()) } override AccessPathApproxCons getApprox() { result = TConsNil(head_) and tail_ = TAccessPathNil() @@ -3586,7 +3614,7 @@ module MakeImpl Lang> { tail.length() = len - 1 } - override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + override AccessPathFrontHead getFront() { result = TFrontHead(head1, len) } override AccessPathApproxCons getApprox() { result = TConsCons(head1, head2, len) or @@ -3618,7 +3646,7 @@ module MakeImpl Lang> { tail.length() = len - 1 } - override AccessPathFrontHead getFront() { result = TFrontHead(head_) } + override AccessPathFrontHead getFront() { result = TFrontHead(head_, len) } override AccessPathApproxCons getApprox() { result = TCons1(head_, len) } diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll index c64f0edb8468..8dbcaa2ce5b5 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplCommon.qll @@ -1797,12 +1797,12 @@ module MakeImplCommon Lang> { cached newtype TAccessPathFront = TFrontNil() or - TFrontHead(Content c) + TFrontHead(Content c, int length) { length in [1 .. accessPathLimit()] } cached newtype TApproxAccessPathFront = TApproxFrontNil() or - TApproxFrontHead(ContentApprox c) + TApproxFrontHead(ContentApprox c, int length) { length in [1 .. accessPathLimit()] } cached newtype TAccessPathFrontOption = @@ -2505,15 +2505,10 @@ module MakeImplCommon Lang> { abstract boolean toBoolNonEmpty(); - ContentApprox getHead() { this = TApproxFrontHead(result) } + ContentApprox getHead(int length) { this = TApproxFrontHead(result, length) } pragma[nomagic] - Content getAHead() { - exists(ContentApprox cont | - this = TApproxFrontHead(cont) and - cont = getContentApproxCached(result) - ) - } + Content getAHead(int length) { this.getHead(length) = getContentApproxCached(result) } } class ApproxAccessPathFrontNil extends ApproxAccessPathFront, TApproxFrontNil { @@ -2524,10 +2519,11 @@ module MakeImplCommon Lang> { class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead { private ContentApprox c; + private int length; - ApproxAccessPathFrontHead() { this = TApproxFrontHead(c) } + ApproxAccessPathFrontHead() { this = TApproxFrontHead(c, length) } - override string toString() { result = c.toString() } + override string toString() { result = c + " (length: " + length + ")" } override boolean toBoolNonEmpty() { result = true } } @@ -2549,7 +2545,7 @@ module MakeImplCommon Lang> { abstract ApproxAccessPathFront toApprox(); - Content getHead() { this = TFrontHead(result) } + Content getHead(int length) { this = TFrontHead(result, length) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { @@ -2560,12 +2556,13 @@ module MakeImplCommon Lang> { class AccessPathFrontHead extends AccessPathFront, TFrontHead { private Content c; + private int length; - AccessPathFrontHead() { this = TFrontHead(c) } + AccessPathFrontHead() { this = TFrontHead(c, length) } - override string toString() { result = c.toString() } + override string toString() { result = c + " (length: " + length + ")" } - override ApproxAccessPathFront toApprox() { result.getAHead() = c } + override ApproxAccessPathFront toApprox() { result.getAHead(length) = c } } /** An optional access path front. */