diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index c6bdcc206b45..e673adff633a 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -2859,12 +2859,17 @@ module MakeImpl Lang> { 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(boolean isSingleton | + result.getAHead(isSingleton) = c and + if tail instanceof ApNil then isSingleton = true else isSingleton = false + ) + } 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 +2915,7 @@ module MakeImpl Lang> { PrevStage::revFlow(node) and PrevStage::readStepCand(_, c, _) and Stage1::expectsContentEx(node, c) and - c = ap.getAHead() + c = ap.getAHead(_) ) } @@ -2961,12 +2966,17 @@ module MakeImpl Lang> { 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(boolean isSingleton | + result.getHead(isSingleton) = c and + if tail instanceof ApNil then isSingleton = true else isSingleton = false + ) + } 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 +3022,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 +3034,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 +3069,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 +3087,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 +3141,7 @@ module MakeImpl Lang> { override int len() { result = 1 } - override AccessPathFront getFront() { result = TFrontHead(c) } + override AccessPathFront getFront() { result = TFrontHead(c, true) } override predicate isCons(Content head, AccessPathApprox tail) { head = c and tail = TNil() } } @@ -3153,7 +3163,7 @@ module MakeImpl Lang> { override int len() { result = len } - override AccessPathFront getFront() { result = TFrontHead(c1) } + override AccessPathFront getFront() { result = TFrontHead(c1, false) } override predicate isCons(Content head, AccessPathApprox tail) { head = c1 and @@ -3184,12 +3194,17 @@ module MakeImpl Lang> { override int len() { result = len } - override AccessPathFront getFront() { result = TFrontHead(c) } + override AccessPathFront getFront() { + if len = 1 then result = TFrontHead(c, true) else result = TFrontHead(c, false) + } override predicate isCons(Content head, AccessPathApprox tail) { head = c and ( - exists(Content c2 | Stage4::consCand(c, TFrontHead(c2)) | + exists(Content c2, boolean isSingleton | + Stage4::consCand(c, TFrontHead(c2, isSingleton)) and + if len > 2 then isSingleton = false else isSingleton = true + | tail = TConsCons(c2, _, len - 1) or len = 2 and @@ -3531,7 +3546,11 @@ module MakeImpl Lang> { override predicate isCons(Content head, AccessPath tail) { head = head_ and tail = tail_ } - override AccessPathFrontHead getFront() { result = TFrontHead(head_) } + override AccessPathFrontHead getFront() { + if this.length() = 1 + then result = TFrontHead(head_, true) + else result = TFrontHead(head_, false) + } override AccessPathApproxCons getApprox() { result = TConsNil(head_) and tail_ = TAccessPathNil() @@ -3586,7 +3605,7 @@ module MakeImpl Lang> { tail.length() = len - 1 } - override AccessPathFrontHead getFront() { result = TFrontHead(head1) } + override AccessPathFrontHead getFront() { result = TFrontHead(head1, false) } override AccessPathApproxCons getApprox() { result = TConsCons(head1, head2, len) or @@ -3618,7 +3637,9 @@ module MakeImpl Lang> { tail.length() = len - 1 } - override AccessPathFrontHead getFront() { result = TFrontHead(head_) } + override AccessPathFrontHead getFront() { + if len = 1 then result = TFrontHead(head_, true) else result = TFrontHead(head_, false) + } 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..9a8eec6dd6b5 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, Boolean isSingleton) cached newtype TApproxAccessPathFront = TApproxFrontNil() or - TApproxFrontHead(ContentApprox c) + TApproxFrontHead(ContentApprox c, Boolean isSingleton) cached newtype TAccessPathFrontOption = @@ -2505,14 +2505,11 @@ module MakeImplCommon Lang> { abstract boolean toBoolNonEmpty(); - ContentApprox getHead() { this = TApproxFrontHead(result) } + ContentApprox getHead(boolean isSingleton) { this = TApproxFrontHead(result, isSingleton) } pragma[nomagic] - Content getAHead() { - exists(ContentApprox cont | - this = TApproxFrontHead(cont) and - cont = getContentApproxCached(result) - ) + Content getAHead(boolean isSingleton) { + this.getHead(isSingleton) = getContentApproxCached(result) } } @@ -2524,10 +2521,13 @@ module MakeImplCommon Lang> { class ApproxAccessPathFrontHead extends ApproxAccessPathFront, TApproxFrontHead { private ContentApprox c; + private boolean isSingleton; - ApproxAccessPathFrontHead() { this = TApproxFrontHead(c) } + ApproxAccessPathFrontHead() { this = TApproxFrontHead(c, isSingleton) } - override string toString() { result = c.toString() } + override string toString() { + if isSingleton = true then result = c.toString() + " (singleton)" else result = c.toString() + } override boolean toBoolNonEmpty() { result = true } } @@ -2549,7 +2549,7 @@ module MakeImplCommon Lang> { abstract ApproxAccessPathFront toApprox(); - Content getHead() { this = TFrontHead(result) } + Content getHead(boolean isSingleton) { this = TFrontHead(result, isSingleton) } } class AccessPathFrontNil extends AccessPathFront, TFrontNil { @@ -2560,12 +2560,15 @@ module MakeImplCommon Lang> { class AccessPathFrontHead extends AccessPathFront, TFrontHead { private Content c; + private boolean isSingleton; - AccessPathFrontHead() { this = TFrontHead(c) } + AccessPathFrontHead() { this = TFrontHead(c, isSingleton) } - override string toString() { result = c.toString() } + override string toString() { + if isSingleton = true then result = c.toString() + " (singleton)" else result = c.toString() + } - override ApproxAccessPathFront toApprox() { result.getAHead() = c } + override ApproxAccessPathFront toApprox() { result.getAHead(isSingleton) = c } } /** An optional access path front. */