From a50f18ab5087b830a29b12c608e613aa5e7bb9ef Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Apr 2022 12:05:13 +0200 Subject: [PATCH 1/5] Data flow: Introduce `expectsContent` --- .../ruby/dataflow/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImplCommon.qll | 3 + 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } From 6e2e8440ebbe37ccdac21f905cf776ca93a271a1 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Apr 2022 12:17:22 +0200 Subject: [PATCH 2/5] Data flow: Sync files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../cpp/dataflow/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../cpp/dataflow/internal/DataFlowImpl3.qll | 65 +++++++++++++++++-- .../cpp/dataflow/internal/DataFlowImpl4.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImplCommon.qll | 3 + .../dataflow/internal/DataFlowImplLocal.qll | 65 +++++++++++++++++-- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../ir/dataflow/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../ir/dataflow/internal/DataFlowImpl3.qll | 65 +++++++++++++++++-- .../ir/dataflow/internal/DataFlowImpl4.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImplCommon.qll | 3 + .../csharp/dataflow/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImpl3.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImpl4.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImpl5.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImplCommon.qll | 3 + .../java/dataflow/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl3.qll | 65 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl4.qll | 65 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl5.qll | 65 +++++++++++++++++-- .../java/dataflow/internal/DataFlowImpl6.qll | 65 +++++++++++++++++-- .../dataflow/internal/DataFlowImplCommon.qll | 3 + .../DataFlowImplForOnActivityResult.qll | 65 +++++++++++++++++-- .../DataFlowImplForSerializability.qll | 65 +++++++++++++++++-- .../dataflow/new/internal/DataFlowImpl.qll | 65 +++++++++++++++++-- .../dataflow/new/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../dataflow/new/internal/DataFlowImpl3.qll | 65 +++++++++++++++++-- .../dataflow/new/internal/DataFlowImpl4.qll | 65 +++++++++++++++++-- .../new/internal/DataFlowImplCommon.qll | 3 + .../ruby/dataflow/internal/DataFlowImpl2.qll | 65 +++++++++++++++++-- .../internal/DataFlowImplForLibraries.qll | 65 +++++++++++++++++-- 33 files changed, 1639 insertions(+), 196 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 100ffde26162..e60505d92480 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -328,6 +328,9 @@ private module Cached { cached predicate clearsContentCached(Node n, ContentSet c) { clearsContent(n, c) } + cached + predicate expectsContentCached(Node n, ContentSet c) { expectsContent(n, c) } + cached predicate isUnreachableInCallCached(Node n, DataFlowCall call) { isUnreachableInCall(n, call) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll index f49d975ccf93..9c945f4e83d1 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll @@ -502,7 +502,7 @@ pragma[inline] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } @@ -511,10 +511,22 @@ pragma[inline] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and - c = cs.getAReadContent() + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() + ) +} + +// inline to reduce fan-out via `getAReadContent` +pragma[inline] +private predicate expectsContentEx(NodeEx n, Content c) { + exists(ContentSet cs | + expectsContentCached(n.asNode(), cs) and + pragma[only_bind_out](c) = pragma[only_bind_into](cs).getAReadContent() ) } +pragma[nomagic] +private predicate notExpectsContent(NodeEx n) { not expectsContentCached(n.asNode(), _) } + pragma[nomagic] private predicate store( NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config @@ -793,7 +805,7 @@ private module Stage1 { * by `revFlow`. */ pragma[nomagic] - private predicate revFlowIsReadAndStored(Content c, Configuration conf) { + predicate revFlowIsReadAndStored(Content c, Configuration conf) { revFlowConsCand(c, conf) and revFlowStore(c, _, _, conf) } @@ -891,7 +903,7 @@ private module Stage1 { pragma[nomagic] predicate readStepCand(NodeEx n1, Content c, NodeEx n2, Configuration config) { - revFlowIsReadAndStored(pragma[only_bind_into](c), pragma[only_bind_into](config)) and + revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and read(n1, c, n2, pragma[only_bind_into](config)) and revFlow(n2, pragma[only_bind_into](config)) } @@ -1181,11 +1193,26 @@ private module Stage2 { private predicate flowIntoCall = flowIntoCallNodeCand1/5; + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::revFlowIsReadAndStored(c, pragma[only_bind_into](config)) and + expectsContentEx(node, c) + ) + } + bindingset[node, state, ap, config] private predicate filter(NodeEx node, FlowState state, Ap ap, Configuration config) { PrevStage::revFlowState(state, pragma[only_bind_into](config)) and exists(ap) and - not stateBarrier(node, state, config) + not stateBarrier(node, state, config) and + ( + notExpectsContent(node) + or + ap = true and + expectsContentCand(node, config) + ) } bindingset[ap, contentType] @@ -1740,7 +1767,8 @@ private module LocalFlowBigStep { private class FlowCheckNode extends NodeEx { FlowCheckNode() { castNode(this.asNode()) or - clearsContentCached(this.asNode(), _) + clearsContentCached(this.asNode(), _) or + expectsContentCached(this.asNode(), _) } } @@ -1979,6 +2007,16 @@ private module Stage3 { clearContent(node, ap.getHead().getContent(), config) } + pragma[nomagic] + private predicate expectsContentCand(NodeEx node, Ap ap, Configuration config) { + exists(Content c | + PrevStage::revFlow(node, pragma[only_bind_into](config)) and + PrevStage::readStepCand(_, c, _, pragma[only_bind_into](config)) and + expectsContentEx(node, c) and + c = ap.getHead().getContent() + ) + } + pragma[nomagic] private predicate castingNodeEx(NodeEx node) { node.asNode() instanceof CastingNode } @@ -1987,7 +2025,12 @@ private module Stage3 { exists(state) and exists(config) and not clear(node, ap, config) and - if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() + (if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), ap.getType()) else any()) and + ( + notExpectsContent(node) + or + expectsContentCand(node, ap, config) + ) } bindingset[ap, contentType] @@ -4609,6 +4652,10 @@ private module FlowExploration { exists(PartialPathNodeRev mid | revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and not clearsContentEx(node, ap.getHead()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead()) + ) and not fullBarrier(node, config) and not stateBarrier(node, state, config) and distSink(node.getEnclosingCallable(), config) <= config.explorationLimit() @@ -4625,6 +4672,10 @@ private module FlowExploration { not fullBarrier(node, config) and not stateBarrier(node, state, config) and not clearsContentEx(node, ap.getHead().getContent()) and + ( + notExpectsContent(node) or + expectsContentEx(node, ap.getHead().getContent()) + ) and if node.asNode() instanceof CastingNode then compatibleTypes(node.getDataFlowType(), ap.getType()) else any() From da72ba46d461d799b12e191e177c729f4ce69168 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Apr 2022 12:17:40 +0200 Subject: [PATCH 3/5] Data flow: Add stub `expectsContent` for all languages --- .../semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll | 6 ++++++ .../code/cpp/ir/dataflow/internal/DataFlowPrivate.qll | 6 ++++++ .../code/csharp/dataflow/internal/DataFlowPrivate.qll | 6 ++++++ .../semmle/code/java/dataflow/internal/DataFlowPrivate.qll | 6 ++++++ .../semmle/python/dataflow/new/internal/DataFlowPrivate.qll | 6 ++++++ .../lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll index 0a44ec3336bd..9ad3e835c381 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowPrivate.qll @@ -198,6 +198,12 @@ predicate clearsContent(Node n, Content c) { none() // stub implementation } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + /** Gets the type of `n` used for type pruning. */ Type getNodeType(Node n) { suppressUnusedNode(n) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index b065f400fa64..9dcd7f176df4 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -279,6 +279,12 @@ predicate clearsContent(Node n, Content c) { none() // stub implementation } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + /** Gets the type of `n` used for type pruning. */ IRType getNodeType(Node n) { suppressUnusedNode(n) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index 60825ea46679..b958415bbee1 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -1714,6 +1714,12 @@ predicate clearsContent(Node n, Content c) { ) } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + /** * Holds if the node `n` is unreachable when the call context is `call`. */ diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 30031931ed92..3111abc2ad76 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -160,6 +160,12 @@ predicate clearsContent(Node n, Content c) { FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + /** * Gets a representative (boxed) type for `t` for the purpose of pruning * possible flow. A single type is used for all numeric types to account for diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll index da0c6ef171bd..a8e812a69720 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll @@ -813,6 +813,12 @@ predicate clearsContent(Node n, Content c) { attributeClearStep(n, c) } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + /** * Holds if values stored inside attribute `c` are cleared at node `n`. * diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index d5b2f44c82f7..228b04caae5a 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -800,6 +800,12 @@ predicate clearsContent(Node n, ContentSet c) { FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) } +/** + * Holds if the value that is being tracked is expected to be stored inside content `c` + * at node `n`. + */ +predicate expectsContent(Node n, ContentSet c) { none() } + private newtype TDataFlowType = TTodoDataFlowType() or TTodoDataFlowType2() // Add a dummy value to prevent bad functionality-induced joins arising from a type of size 1. From ac3bfa1788468b69422ee7042c1495e52e37ebfb Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Apr 2022 12:19:38 +0200 Subject: [PATCH 4/5] Data flow: Mention `expectsContent` in `dataflow.md` --- docs/ql-libraries/dataflow/dataflow.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/ql-libraries/dataflow/dataflow.md b/docs/ql-libraries/dataflow/dataflow.md index 2ce0e308a16a..1b6d52ee994b 100644 --- a/docs/ql-libraries/dataflow/dataflow.md +++ b/docs/ql-libraries/dataflow/dataflow.md @@ -509,6 +509,12 @@ use-use steps. If local flow is implemented using def-use steps, then Note that `clearsContent(n, cs)` is interpreted using `cs.getAReadContent()`. +Dually, there exists a predicate +```ql +predicate expectsContent(Node n, ContentSet c); +``` +which acts as a barrier when data is _not_ stored inside one of `c.getAReadContent()`. + ## Type pruning The library supports pruning paths when a sequence of value-preserving steps From 74e99302d6f8b5453afff91c0734a73fc46acd69 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 3 May 2022 16:13:50 +0200 Subject: [PATCH 5/5] Address review comments --- .../lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll | 6 +++--- .../lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll | 6 +++--- .../lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll | 6 +++--- .../lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll | 6 +++--- .../semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll | 6 +++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll | 6 +++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll | 6 +++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll | 6 +++--- .../semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll | 6 +++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl.qll | 6 +++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll | 6 +++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll | 6 +++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll | 6 +++--- .../semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll | 6 +++--- .../lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll | 6 +++--- .../semmle/code/java/dataflow/internal/DataFlowImpl2.qll | 6 +++--- .../semmle/code/java/dataflow/internal/DataFlowImpl3.qll | 6 +++--- .../semmle/code/java/dataflow/internal/DataFlowImpl4.qll | 6 +++--- .../semmle/code/java/dataflow/internal/DataFlowImpl5.qll | 6 +++--- .../semmle/code/java/dataflow/internal/DataFlowImpl6.qll | 6 +++--- .../dataflow/internal/DataFlowImplForOnActivityResult.qll | 6 +++--- .../dataflow/internal/DataFlowImplForSerializability.qll | 6 +++--- .../semmle/python/dataflow/new/internal/DataFlowImpl.qll | 6 +++--- .../semmle/python/dataflow/new/internal/DataFlowImpl2.qll | 6 +++--- .../semmle/python/dataflow/new/internal/DataFlowImpl3.qll | 6 +++--- .../semmle/python/dataflow/new/internal/DataFlowImpl4.qll | 6 +++--- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll | 6 +++--- ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll | 6 +++--- .../ruby/dataflow/internal/DataFlowImplForLibraries.qll | 6 +++--- 29 files changed, 87 insertions(+), 87 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImpl6.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForOnActivityResult.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplForSerializability.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll index 9c945f4e83d1..c7b4e5e4cff6 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll @@ -498,7 +498,7 @@ private predicate readSet(NodeEx node1, ContentSet c, NodeEx node2, Configuratio } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) { exists(ContentSet cs | readSet(node1, cs, node2, config) and @@ -507,7 +507,7 @@ private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration conf } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate clearsContentEx(NodeEx n, Content c) { exists(ContentSet cs | clearsContentCached(n.asNode(), cs) and @@ -516,7 +516,7 @@ private predicate clearsContentEx(NodeEx n, Content c) { } // inline to reduce fan-out via `getAReadContent` -pragma[inline] +bindingset[c] private predicate expectsContentEx(NodeEx n, Content c) { exists(ContentSet cs | expectsContentCached(n.asNode(), cs) and