diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index cf6539e39d7..b45c4ca0684 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index cf6539e39d7..b45c4ca0684 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index cf6539e39d7..b45c4ca0684 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index cf6539e39d7..b45c4ca0684 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index cf6539e39d7..b45c4ca0684 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index cf6539e39d7..b45c4ca0684 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index cf6539e39d7..b45c4ca0684 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index cf6539e39d7..b45c4ca0684 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index cf6539e39d7..b45c4ca0684 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index cf6539e39d7..b45c4ca0684 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index cf6539e39d7..b45c4ca0684 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -2048,11 +2048,64 @@ private module FlowExploration { result = distSrcExt(TCallable(c, config)) - 1 } + private newtype TPartialAccessPath = + TPartialNil(DataFlowType t) or + TPartialCons(Content f, int len) { len in [1 .. 5] } + + /** + * Conceptually a list of `Content`s followed by a `Type`, but only the first + * element of the list and its length are tracked. If data flows from a source to + * a given node with a given `AccessPath`, this indicates the sequence of + * dereference operations needed to get from the value in the node to the + * tracked object. The final type indicates the type of the tracked object. + */ + private class PartialAccessPath extends TPartialAccessPath { + abstract string toString(); + + Content getHead() { this = TPartialCons(result, _) } + + int len() { + this = TPartialNil(_) and result = 0 + or + this = TPartialCons(_, result) + } + + DataFlowType getType() { + this = TPartialNil(result) + or + exists(Content head | this = TPartialCons(head, _) | result = head.getContainerType()) + } + + abstract AccessPathFront getFront(); + } + + private class PartialAccessPathNil extends PartialAccessPath, TPartialNil { + override string toString() { + exists(DataFlowType t | this = TPartialNil(t) | result = ppReprType(t)) + } + + override AccessPathFront getFront() { + exists(DataFlowType t | this = TPartialNil(t) | result = TFrontNil(t)) + } + } + + private class PartialAccessPathCons extends PartialAccessPath, TPartialCons { + override string toString() { + exists(Content f, int len | this = TPartialCons(f, len) | + result = f.toString() + ", ... (" + len.toString() + ")" + ) + } + + override AccessPathFront getFront() { + exists(Content f | this = TPartialCons(f, _) | result = TFrontHead(f)) + } + } + private newtype TPartialPathNode = - TPartialPathNodeMk(Node node, CallContext cc, AccessPath ap, Configuration config) { + TPartialPathNodeMk(Node node, CallContext cc, PartialAccessPath ap, Configuration config) { config.isSource(node) and cc instanceof CallContextAny and - ap = TNil(getErasedRepr(node.getType())) and + ap = TPartialNil(getErasedRepr(node.getType())) and not fullBarrier(node, config) and exists(config.explorationLimit()) or @@ -2062,7 +2115,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathNodeMk0( - Node node, CallContext cc, AccessPath ap, Configuration config + Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(PartialPathNode mid | partialPathStep(mid, node, cc, ap, config) and @@ -2138,7 +2191,7 @@ private module FlowExploration { CallContext cc; - AccessPath ap; + PartialAccessPath ap; Configuration config; @@ -2148,7 +2201,7 @@ private module FlowExploration { CallContext getCallContext() { result = cc } - AccessPath getAp() { result = ap } + PartialAccessPath getAp() { result = ap } override Configuration getConfiguration() { result = config } @@ -2161,7 +2214,7 @@ private module FlowExploration { } private predicate partialPathStep( - PartialPathNodePriv mid, Node node, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config ) { localFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and @@ -2170,8 +2223,8 @@ private module FlowExploration { or additionalLocalFlowStep(mid.getNode(), node, config) and cc = mid.getCallContext() and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or jumpStep(mid.getNode(), node, config) and @@ -2181,15 +2234,15 @@ private module FlowExploration { or additionalJumpStep(mid.getNode(), node, config) and cc instanceof CallContextAny and - mid.getAp() instanceof AccessPathNil and - ap = TNil(getErasedRepr(node.getType())) and + mid.getAp() instanceof PartialAccessPathNil and + ap = TPartialNil(getErasedRepr(node.getType())) and config = mid.getConfiguration() or partialPathStoreStep(mid, _, _, node, ap) and cc = mid.getCallContext() and config = mid.getConfiguration() or - exists(AccessPath ap0, Content f | + exists(PartialAccessPath ap0, Content f | partialPathReadStep(mid, ap0, f, node, cc, config) and apConsFwd(ap, f, ap0, config) ) @@ -2210,7 +2263,7 @@ private module FlowExploration { pragma[inline] private predicate partialPathStoreStep( - PartialPathNodePriv mid, AccessPath ap1, Content f, Node node, AccessPath ap2 + PartialPathNodePriv mid, PartialAccessPath ap1, Content f, Node node, PartialAccessPath ap2 ) { ap1 = mid.getAp() and store(mid.getNode(), f, node) and @@ -2220,7 +2273,9 @@ private module FlowExploration { } pragma[nomagic] - private predicate apConsFwd(AccessPath ap1, Content f, AccessPath ap2, Configuration config) { + private predicate apConsFwd( + PartialAccessPath ap1, Content f, PartialAccessPath ap2, Configuration config + ) { exists(PartialPathNodePriv mid | partialPathStoreStep(mid, ap1, f, _, ap2) and config = mid.getConfiguration() @@ -2229,7 +2284,7 @@ private module FlowExploration { pragma[nomagic] private predicate partialPathReadStep( - PartialPathNodePriv mid, AccessPath ap, Content f, Node node, CallContext cc, + PartialPathNodePriv mid, PartialAccessPath ap, Content f, Node node, CallContext cc, Configuration config ) { ap = mid.getAp() and @@ -2240,7 +2295,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable0( - PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, AccessPath ap, + PartialPathNodePriv mid, ReturnPosition pos, CallContext innercc, PartialAccessPath ap, Configuration config ) { pos = getReturnPosition(mid.getNode()) and @@ -2252,8 +2307,8 @@ private module FlowExploration { pragma[noinline] private predicate partialPathOutOfCallable1( - PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + PartialPathNodePriv mid, DataFlowCall call, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ReturnPosition pos, DataFlowCallable c, CallContext innercc | partialPathOutOfCallable0(mid, pos, innercc, ap, config) and @@ -2266,7 +2321,7 @@ private module FlowExploration { } private predicate partialPathOutOfCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(ReturnKind kind, DataFlowCall call | partialPathOutOfCallable1(mid, call, kind, cc, ap, config) @@ -2276,7 +2331,7 @@ private module FlowExploration { } private predicate partialPathOutOfArgument( - PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, AccessPath ap, + PartialPathNodePriv mid, PostUpdateNode node, CallContext cc, PartialAccessPath ap, Configuration config ) { exists( @@ -2302,7 +2357,7 @@ private module FlowExploration { pragma[noinline] private predicate partialPathIntoArg( PartialPathNodePriv mid, int i, CallContext cc, DataFlowCall call, boolean emptyAp, - AccessPath ap, Configuration config + PartialAccessPath ap, Configuration config ) { exists(ArgumentNode arg | arg = mid.getNode() and @@ -2311,16 +2366,16 @@ private module FlowExploration { ap = mid.getAp() and config = mid.getConfiguration() | - ap instanceof AccessPathNil and emptyAp = true + ap instanceof PartialAccessPathNil and emptyAp = true or - ap instanceof AccessPathCons and emptyAp = false + ap instanceof PartialAccessPathCons and emptyAp = false ) } pragma[nomagic] private predicate partialPathIntoCallable0( PartialPathNodePriv mid, DataFlowCallable callable, int i, CallContext outercc, - DataFlowCall call, boolean emptyAp, AccessPath ap, Configuration config + DataFlowCall call, boolean emptyAp, PartialAccessPath ap, Configuration config ) { partialPathIntoArg(mid, i, outercc, call, emptyAp, ap, config) and callable = resolveCall(call, outercc) @@ -2328,7 +2383,7 @@ private module FlowExploration { private predicate partialPathIntoCallable( PartialPathNodePriv mid, ParameterNode p, CallContext outercc, CallContextCall innercc, - DataFlowCall call, AccessPath ap, Configuration config + DataFlowCall call, PartialAccessPath ap, Configuration config ) { exists(int i, DataFlowCallable callable, boolean emptyAp | partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and @@ -2342,7 +2397,8 @@ private module FlowExploration { pragma[nomagic] private predicate paramFlowsThroughInPartialPath( - ParameterNode p, ReturnKind kind, CallContextCall cc, AccessPathNil apnil, Configuration config + ParameterNode p, ReturnKind kind, CallContextCall cc, PartialAccessPathNil apnil, + Configuration config ) { exists(PartialPathNodePriv mid, ReturnNode ret | mid.getNode() = ret and @@ -2362,9 +2418,9 @@ private module FlowExploration { pragma[noinline] private predicate partialPathThroughCallable0( DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, - AccessPathNil apnil, Configuration config + PartialAccessPathNil apnil, Configuration config ) { - exists(ParameterNode p, CallContext innercc, AccessPathNil midapnil | + exists(ParameterNode p, CallContext innercc, PartialAccessPathNil midapnil | partialPathIntoCallable(mid, p, cc, innercc, call, midapnil, config) and paramFlowsThroughInPartialPath(p, kind, innercc, apnil, config) and not parameterValueFlowsThrough(p, kind, innercc) @@ -2372,7 +2428,8 @@ private module FlowExploration { } private predicate partialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPathNil apnil, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPathNil apnil, + Configuration config ) { exists(DataFlowCall call, ReturnKind kind | partialPathThroughCallable0(call, mid, kind, cc, apnil, config) and @@ -2382,8 +2439,8 @@ private module FlowExploration { pragma[noinline] private predicate valuePartialPathThroughCallable0( - DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, AccessPath ap, - Configuration config + DataFlowCall call, PartialPathNodePriv mid, ReturnKind kind, CallContext cc, + PartialAccessPath ap, Configuration config ) { exists(ParameterNode p, CallContext innercc | partialPathIntoCallable(mid, p, cc, innercc, call, ap, config) and @@ -2392,7 +2449,7 @@ private module FlowExploration { } private predicate valuePartialPathThroughCallable( - PartialPathNodePriv mid, OutNode out, CallContext cc, AccessPath ap, Configuration config + PartialPathNodePriv mid, OutNode out, CallContext cc, PartialAccessPath ap, Configuration config ) { exists(DataFlowCall call, ReturnKind kind | valuePartialPathThroughCallable0(call, mid, kind, cc, ap, config) and diff --git a/java/ql/test/library-tests/dataflow/partial/test.expected b/java/ql/test/library-tests/dataflow/partial/test.expected index dbdd45a8908..3e33025db43 100644 --- a/java/ql/test/library-tests/dataflow/partial/test.expected +++ b/java/ql/test/library-tests/dataflow/partial/test.expected @@ -1,4 +1,14 @@ edges +| A.java:12:5:12:5 | b [post update] [elem, ... (1)] | A.java:13:12:13:12 | b [elem, ... (1)] | +| A.java:12:14:12:18 | src(...) [Object] | A.java:12:5:12:5 | b [post update] [elem, ... (1)] | | A.java:12:14:12:18 | src(...) [Object] | A.java:12:5:12:18 | ...=... [Object] | +| A.java:13:12:13:12 | b [elem, ... (1)] | A.java:17:13:17:16 | f1(...) [elem, ... (1)] | +| A.java:17:13:17:16 | f1(...) [elem, ... (1)] | A.java:18:8:18:8 | b [elem, ... (1)] | +| A.java:18:8:18:8 | b [elem, ... (1)] | A.java:21:11:21:15 | b [elem, ... (1)] | #select +| 0 | A.java:12:5:12:5 | b [post update] [elem, ... (1)] | | 0 | A.java:12:5:12:18 | ...=... [Object] | +| 0 | A.java:13:12:13:12 | b [elem, ... (1)] | +| 1 | A.java:17:13:17:16 | f1(...) [elem, ... (1)] | +| 1 | A.java:18:8:18:8 | b [elem, ... (1)] | +| 2 | A.java:21:11:21:15 | b [elem, ... (1)] |