diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index db8f0bd0213..bc363d86ee2 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -1325,7 +1325,7 @@ import IsUnreachableInCall * Holds if access paths with `c` at their head always should be tracked at high * precision. This disables adaptive access path precision for such access paths. */ -predicate forceHighPrecision(Content c) { none() } +predicate forceHighPrecision(Content c) { c instanceof ElementContent } /** Holds if `n` should be hidden from path explanations. */ predicate nodeIsHidden(Node n) { @@ -1396,7 +1396,8 @@ private predicate unionHasApproxName(Cpp::Union u, string s) { s = u.getName().c cached private newtype TContentApprox = TFieldApproxContent(string s) { fieldHasApproxName(_, s) } or - TUnionApproxContent(string s) { unionHasApproxName(_, s) } + TUnionApproxContent(string s) { unionHasApproxName(_, s) } or + TElementApproxContent() /** An approximated `Content`. */ class ContentApprox extends TContentApprox { @@ -1427,6 +1428,10 @@ private class UnionApproxContent extends ContentApprox, TUnionApproxContent { final override string toString() { result = s } } +private class ElementApproxContent extends ContentApprox, TElementApproxContent { + final override string toString() { result = "ElementApprox" } +} + /** Gets an approximated value for content `c`. */ pragma[inline] ContentApprox getContentApprox(Content c) { @@ -1441,6 +1446,9 @@ ContentApprox getContentApprox(Content c) { u = c.(UnionContent).getUnion() and unionHasApproxName(u, prefix) ) + or + c instanceof ElementContent and + result instanceof ElementApproxContent } /** @@ -1700,6 +1708,14 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope { /** Gets the second-level scope containing the node `n`, if any. */ DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n } +/** + * Gets the maximum number of indirections to use for `ElementContent`. + * + * This should be equal to the largest number of stars (i.e., `*`s) in any + * `Element` content across all of our MaD summaries, sources, and sinks. + */ +int getMaxElementContentIndirectionIndex() { result = 5 } + /** * Module that defines flow through iterators. * For example, diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index f798c4dba21..f2263abf7f5 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -2083,6 +2083,9 @@ private newtype TContent = indirectionIndex = [1 .. max(Ssa::getMaxIndirectionsForType(getAFieldWithSize(u, bytes).getUnspecifiedType()))] ) + } or + TElementContent(int indirectionIndex) { + indirectionIndex = [1 .. getMaxElementContentIndirectionIndex()] } /** @@ -2193,6 +2196,25 @@ class UnionContent extends Content, TUnionContent { } } +/** + * A `Content` that represents one of the elements of a + * container (e.g., `std::vector`). + */ +class ElementContent extends Content, TElementContent { + int indirectionIndex; + + ElementContent() { this = TElementContent(indirectionIndex) } + + pragma[inline] + override int getIndirectionIndex() { + pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex) + } + + override predicate impliesClearOf(Content c) { none() } + + override string toString() { result = contentStars(this) + "element" } +} + /** * An entity that represents a set of `Content`s. * diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll index 4b421bbe5e5..e570ecb0542 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll @@ -147,7 +147,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, st * of `c` at sinks and inputs to additional taint steps. */ bindingset[node] -predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() } +predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { + node instanceof ArgumentNode and + c.isSingleton(any(ElementContent ec)) +} /** * Holds if `node` should be a sanitizer in all global taint flow configurations