diff --git a/cpp/ql/lib/ext/empty.model.yml b/cpp/ql/lib/ext/empty.model.yml index e5202b5ad73c..196ff51bcbca 100644 --- a/cpp/ql/lib/ext/empty.model.yml +++ b/cpp/ql/lib/ext/empty.model.yml @@ -21,3 +21,7 @@ extensions: pack: codeql/cpp-all extensible: summaryModel data: [] + - addsTo: + pack: codeql/cpp-all + extensible: forwardsModel + data: [] diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index 4f84b30d557e..37bfd2738eae 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -15,6 +15,8 @@ * `namespace; type; subtypes; name; signature; ext; output; kind; provenance` * - BarrierGuards: * `namespace; type; subtypes; name; signature; ext; input; acceptingValue; kind; provenance` + * - Forwards: + * `namespace; type; subtypes; name; signature; ext; start; constructor; provenance` * * The interpretation of a row is similar to API-graphs with a left-to-right * reading. @@ -160,6 +162,20 @@ predicate summaryModel( ) } +/** + * Holds if a forward model exists for the given parameters. + */ +predicate forwardsModel( + string namespace, string type, boolean subtypes, string name, string signature, string ext, + string start, string constructor, string provenance, string model +) { + exists(QlBuiltins::ExtensionId madId | + Extensions::forwardsModel(namespace, type, subtypes, name, signature, ext, start, constructor, + provenance, madId) and + model = madId.toString() + ) +} + /** Provides a query predicate to check the data for validation errors. */ module ModelValidation { private string getInvalidModelInput() { @@ -259,7 +275,8 @@ private predicate elementSpec( sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or barrierModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) or barrierGuardModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) or - summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) + summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) or + forwardsModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) } /** @@ -596,6 +613,14 @@ private string getAtIndex(string s, int i) { not (s = "" and i = 0) } +/** Gets the number of comma-separated arguments in `s`. */ +bindingset[s] +private int getNumberOfArguments(string s) { + s = "" and result = 0 + or + s != "" and result = count(s.indexOf(",")) + 1 +} + /** * Normalizes `partiallyNormalizedSignature` by replacing the `remaining` * number of template arguments in `partiallyNormalizedSignature` with their @@ -605,7 +630,7 @@ private string getSignatureWithoutClassTemplateNames( string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining ) { elementSpecWithArguments0(_, _, _, partiallyNormalizedSignature, typeArgs, nameArgs) and - remaining = count(partiallyNormalizedSignature.indexOf(",")) + 1 and + remaining = getNumberOfArguments(typeArgs) and result = partiallyNormalizedSignature or exists(string mid | @@ -619,7 +644,7 @@ private string getSignatureWithoutClassTemplateNames( ) or // Make sure `remaining` is properly bound - remaining = [0 .. count(partiallyNormalizedSignature.indexOf(",")) + 1] and + remaining = [0 .. getNumberOfArguments(typeArgs)] and not exists(getAtIndex(typeArgs, remaining)) and result = mid ) @@ -636,7 +661,7 @@ pragma[nomagic] private string getSignatureWithoutFunctionTemplateNames( string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining ) { - remaining = count(partiallyNormalizedSignature.indexOf(",")) + 1 and + remaining = getNumberOfArguments(nameArgs) and result = getSignatureWithoutClassTemplateNames(partiallyNormalizedSignature, typeArgs, nameArgs, 0) or @@ -651,7 +676,7 @@ private string getSignatureWithoutFunctionTemplateNames( ) or // Make sure `remaining` is properly bound - remaining = [0 .. count(partiallyNormalizedSignature.indexOf(",")) + 1] and + remaining = [0 .. getNumberOfArguments(nameArgs)] and not exists(getAtIndex(nameArgs, remaining)) and result = mid ) @@ -1046,6 +1071,46 @@ private module Cached { import Cached +/** Gets the constructor type selected by `constructorType` in a forwarding model. */ +bindingset[forwarder, type, name, constructorType] +private Type getForwardedConstructorType( + Function forwarder, string type, string name, string constructorType +) { + exists(string typeArguments, int index | + parseAngles(type, _, typeArguments, "") and + constructorType = getAtIndex(typeArguments, index) and + result = forwarder.getDeclaringType().getTemplateArgument(index) + ) + or + exists(string nameArguments, int index | + parseAngles(name, _, nameArguments, "") and + constructorType = getAtIndex(nameArguments, index) and + result = forwarder.getTemplateArgument(index) + ) +} + +/** Holds if `forwarder` forwards its arguments starting at `start` to `constructor`. */ +predicate forwards(Function forwarder, Constructor constructor, int start) { + exists( + string namespace, string type, boolean subtypes, string name, string signature, string ext, + string startString, string constructorType + | + forwardsModel(namespace, type, subtypes, name, signature, ext, startString, constructorType, _, + _) and + forwarder = interpretElement(namespace, type, subtypes, name, signature, ext) and + start = startString.toInt() + | + // Either the row specifies forwarding to a type given by the type or + // function template, in which case we need to resolve that from the type + // or function name. + constructor.getDeclaringType() = + getForwardedConstructorType(forwarder, type, name, constructorType).getUnspecifiedType() + or + // Or the row specifies forwarding to a specific type. + classHasQualifiedName(constructor.getDeclaringType(), namespace, constructorType) + ) +} + /** * Holds if `node` is specified as a source with the given kind in a MaD flow * model. diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll index 22c74c2aa714..b1617072c33a 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/ExternalFlowExtensions.qll @@ -44,6 +44,14 @@ extensible predicate summaryModel( string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId ); +/** + * Holds if an external constructor forwarding model exists for the given parameters. + */ +extensible predicate forwardsModel( + string namespace, string type, boolean subtypes, string name, string signature, string ext, + string start, string constructor, string provenance, QlBuiltins::ExtensionId madId +); + /** * Holds if a neutral model exists for the given parameters. */ diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll index 176b95933db8..6c613308d5f4 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll @@ -111,6 +111,9 @@ module Input implements InputSig { pos = -1 and result = TIndirectionPosition(pos, indirection + 1) ) ) + or + argString = "forward" and + result = TForwardPosition() } bindingset[token] diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll index 541b6d13b149..0eb197e4d4cc 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll @@ -191,6 +191,9 @@ private module Cached { } or TSsaSynthNode(SsaImpl::SynthNode n) or TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or + TForwarderConstructorArgumentNode(CallInstruction call) { + isForwarderConstructorArgumentNodeImpl(call) + } or TRawIndirectOperand0(Node0Impl node, int indirectionIndex) { SsaImpl::hasRawIndirectOperand(node.asOperand(), indirectionIndex) } or 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 551035c5589e..f4cb4f14ac74 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 @@ -593,6 +593,89 @@ private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode } } +private Type stripReferences(Type type) { + exists(Type unspecifiedType | unspecifiedType = type.getUnspecifiedType() | + result = unspecifiedType.(Cpp::ReferenceType).getBaseType().getUnspecifiedType() + or + not unspecifiedType instanceof Cpp::ReferenceType and + result = unspecifiedType + ) +} + +private predicate forwardingCallTargetsConstructor( + CallInstruction call, Cpp::Constructor constructor +) { + exists(int start | + External::forwards(call.getStaticCallTarget(), constructor, start) and + call.getNumberOfPositionalArguments() = start + constructor.getNumberOfParameters() and + forall(int i, Type typeCall, Type typeConstructor | + i = [0 .. constructor.getNumberOfParameters() - 1] and + typeCall = stripReferences(call.getPositionalArgument(start + i).getResultType()) and + typeConstructor = stripReferences(constructor.getParameter(i).getUnspecifiedType()) + | + typeCall = typeConstructor + ) + ) +} + +/** Holds if `call` is a call that forwards arguments to a constructor call. */ +predicate isForwarderConstructorArgumentNodeImpl(CallInstruction call) { + forwardingCallTargetsConstructor(call, _) +} + +/** + * In order to implement a MaD summary for a flow such as: + * ``` + * struct Foo { + * int x; + * Foo(int x) { // (2) + * this->x = x; + * } + * } + * + * std::vector v; + * int x = source(); + * v.emplace_back(x); // (1) + * sink(v.back()); + * ``` + * we model it as if the code was: + * ``` + * v.__emplace_back(x, &Foo) + * ``` + * (nevermind that this is not real C++ since you cannot take the address of a + * constructor.) + * where `__emplace_back` invokes `Foo` with the `x` argument and returns the + * result. + * + * This class serves as the argument node for `&Foo`. + */ +private class ForwarderConstructorArgumentNode extends ArgumentNode, + TForwarderConstructorArgumentNode +{ + private CallInstruction call; + + ForwarderConstructorArgumentNode() { this = TForwarderConstructorArgumentNode(call) } + + override predicate sourceArgumentOf(CallInstruction c, ArgumentPosition pos) { + c = call and pos = TForwardPosition() + } + + /** + * Gets a constructor which may be targeted by this forwarding call. + */ + Cpp::Constructor getAConstructor() { forwardingCallTargetsConstructor(call, result) } + + override DataFlowCallable getEnclosingCallable() { + result.asSourceCallable() = this.getFunction() + } + + override Declaration getFunction() { result = call.getEnclosingFunction() } + + override Location getLocationImpl() { result = call.getLocation() } + + override string toStringImpl() { result = "forwarder for " + call.toString() } +} + /** * An argument node that is part of a summary. These only occur when the * summary contains a synthesized call. @@ -672,6 +755,12 @@ abstract class Position extends TPosition { this.getArgumentIndex() = -1 and result = call.getQualifier() } + + /** + * Holds if this position is the synthetic argument for an address of a + * constructor used for functions which perform "perfect forwarding". + */ + predicate isForward() { none() } } class DirectPosition extends Position, TDirectPosition { @@ -721,6 +810,16 @@ class FlowSummaryPosition extends Position, TFlowSummaryPosition { final override int getIndirectionIndex() { result = rk.getIndirectionIndex() } } +class ForwardPosition extends Position, TForwardPosition { + final override predicate isForward() { any() } + + override int getArgumentIndex() { none() } + + final override int getIndirectionIndex() { result = 0 } + + override string toString() { result = "forward" } +} + newtype TPosition = TDirectPosition(int argumentIndex) { exists(any(CallInstruction c).getArgument(argumentIndex)) @@ -740,6 +839,7 @@ newtype TPosition = indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] ) } or + TForwardPosition() or TFlowSummaryPosition(ReturnKind rk) { FlowSummaryImpl::Private::relevantFlowSummaryPosition(rk) } private newtype TReturnKind = @@ -1258,6 +1358,19 @@ private predicate summarizedCallableIsManual(SummarizedCallable sc) { sc.asSummarizedCallable().hasManualModel() } +private DataFlowCallable getTarget(Declaration target) { + // Don't use the source callable if there is a manual model for the target. + not exists(SummarizedCallable sc | + sc.asSummarizedCallable() = target and + summarizedCallableIsManual(sc) + ) and + result.asSourceCallable() = target + or + // When there is no function body, or when we have a manual model, dispatch to the summary. + (not target.hasDefinition() or summarizedCallableIsManual(result)) and + result.asSummarizedCallable() = target +} + /** * A function call relevant for data flow. This includes calls from source * code and calls inside library callables with a flow summary. @@ -1293,20 +1406,7 @@ class DataFlowCall extends TDataFlowCall { * whether is it manual or generated. */ final DataFlowCallable getStaticCallTarget() { - exists(Declaration target | target = this.getStaticCallSourceTarget() | - // Don't use the source callable if there is a manual model for the - // target - not exists(SummarizedCallable sc | - sc.asSummarizedCallable() = target and - summarizedCallableIsManual(sc) - ) and - result.asSourceCallable() = target - or - // When there is no function body, or when we have a manual model then - // we dispatch to the summary. - (not target.hasDefinition() or summarizedCallableIsManual(result)) and - result.asSummarizedCallable() = target - ) + result = getTarget(this.getStaticCallSourceTarget()) } /** @@ -1493,6 +1593,8 @@ predicate nodeIsHidden(Node n) { n instanceof SsaSynthNode or n.(FlowSummaryNode).getSummaryNode().isHidden() + or + n instanceof ForwarderConstructorArgumentNode } predicate neverSkipInPathGraph(Node n) { @@ -1574,6 +1676,9 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) kind.isFunctionPointer() and creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable() or + kind.isFunctionPointer() and + c = getTarget(creation.(ForwarderConstructorArgumentNode).getAConstructor()) + or kind.isFunctor() and exists(OperatorCall operator | operator = c.asSourceCallable() | isFunctorCreationWithoutConstructor(creation, operator) diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index b7dcd4d8f754..4d26df9726b3 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -1706,6 +1706,13 @@ class CallInstruction extends Instruction { result.getIndex() = index } + /** + * Gets a positional argument operand, if any. + */ + final PositionalArgumentOperand getAPositionalArgumentOperand() { + result = this.getPositionalArgumentOperand(_) + } + /** * Gets the argument at the specified index. */ @@ -1714,6 +1721,11 @@ class CallInstruction extends Instruction { result = this.getPositionalArgumentOperand(index).getDef() } + /** + * Gets a positional argument, if any. + */ + final Instruction getAPositionalArgument() { result = this.getPositionalArgument(_) } + /** * Gets the argument operand at the specified index, or `this` if `index` is `-1`. */ @@ -1735,6 +1747,11 @@ class CallInstruction extends Instruction { */ final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) } + /** + * Gets the number of positional arguments of the call. + */ + final int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } + /** * Holds if the result is a side effect for the argument at the specified index, or `this` if * `index` is `-1`. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll index b7dcd4d8f754..4d26df9726b3 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -1706,6 +1706,13 @@ class CallInstruction extends Instruction { result.getIndex() = index } + /** + * Gets a positional argument operand, if any. + */ + final PositionalArgumentOperand getAPositionalArgumentOperand() { + result = this.getPositionalArgumentOperand(_) + } + /** * Gets the argument at the specified index. */ @@ -1714,6 +1721,11 @@ class CallInstruction extends Instruction { result = this.getPositionalArgumentOperand(index).getDef() } + /** + * Gets a positional argument, if any. + */ + final Instruction getAPositionalArgument() { result = this.getPositionalArgument(_) } + /** * Gets the argument operand at the specified index, or `this` if `index` is `-1`. */ @@ -1735,6 +1747,11 @@ class CallInstruction extends Instruction { */ final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) } + /** + * Gets the number of positional arguments of the call. + */ + final int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } + /** * Holds if the result is a side effect for the argument at the specified index, or `this` if * `index` is `-1`. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index b7dcd4d8f754..4d26df9726b3 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -1706,6 +1706,13 @@ class CallInstruction extends Instruction { result.getIndex() = index } + /** + * Gets a positional argument operand, if any. + */ + final PositionalArgumentOperand getAPositionalArgumentOperand() { + result = this.getPositionalArgumentOperand(_) + } + /** * Gets the argument at the specified index. */ @@ -1714,6 +1721,11 @@ class CallInstruction extends Instruction { result = this.getPositionalArgumentOperand(index).getDef() } + /** + * Gets a positional argument, if any. + */ + final Instruction getAPositionalArgument() { result = this.getPositionalArgument(_) } + /** * Gets the argument operand at the specified index, or `this` if `index` is `-1`. */ @@ -1735,6 +1747,11 @@ class CallInstruction extends Instruction { */ final int getNumberOfArguments() { result = count(this.getAnArgumentOperand()) } + /** + * Gets the number of positional arguments of the call. + */ + final int getNumberOfPositionalArguments() { result = count(this.getAPositionalArgument()) } + /** * Holds if the result is a side effect for the argument at the specified index, or `this` if * `index` is `-1`. diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index 65817b549a90..58c58c40a799 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -85,24 +85,28 @@ models | 84 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | | 85 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | | 86 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 87 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 88 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | -| 89 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | -| 90 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | -| 91 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | -| 92 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | -| 93 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 94 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 95 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 96 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 97 | Summary: BloombergLP::bdlbb; Blob; true; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 98 | Summary: BloombergLP::bdlbb; BlobBuffer; true; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 99 | Summary: BloombergLP::bdlbb; BlobBuffer; true; data; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 100 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const Blob &,int,int); ; Argument[*2]; Argument[*0]; taint; manual | -| 101 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const char *,int); ; Argument[*2]; Argument[*0]; taint; manual | -| 102 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (char *,const Blob &,int,int); ; Argument[*1]; Argument[*0]; taint; manual | -| 103 | Summary: BloombergLP::bdlbb; BlobUtil; true; getContiguousRangeOrCopy; ; ; Argument[*1]; ReturnValue[*]; taint; manual | -| 104 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 87 | Summary: ; Container; true; emplace; ; ; Argument[*0]; Argument[forward].Parameter[0]; value; manual | +| 88 | Summary: ; Container; true; get; ; ; Argument[-1].Element; ReturnValue[*]; value; manual | +| 89 | Summary: ; Forwarder; true; forward; ; ; Argument[*0]; Argument[forward].Parameter[0]; value; manual | +| 90 | Summary: ; Forwarder; true; get; ; ; Argument[-1]; ReturnValue; value; manual | +| 91 | Summary: ; MyString; true; operator[]; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 92 | Summary: ; MyString; true; operator[]; ; ; ReturnValue[*]; Argument[-1]; taint; manual | +| 93 | Summary: ; ReverseFlow; true; get_ptr; ; ; ReturnValue[*]; Argument[-1].Field[ReverseFlow::value]; value; manual | +| 94 | Summary: ; TemplateClass1; true; templateFunction2; (U,V); ; Argument[1]; ReturnValue; value; manual | +| 95 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 96 | Summary: ; TemplateClass2; true; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 97 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 98 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 99 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 100 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 101 | Summary: BloombergLP::bdlbb; Blob; true; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 102 | Summary: BloombergLP::bdlbb; BlobBuffer; true; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 103 | Summary: BloombergLP::bdlbb; BlobBuffer; true; data; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 104 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const Blob &,int,int); ; Argument[*2]; Argument[*0]; taint; manual | +| 105 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const char *,int); ; Argument[*2]; Argument[*0]; taint; manual | +| 106 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (char *,const Blob &,int,int); ; Argument[*1]; Argument[*0]; taint; manual | +| 107 | Summary: BloombergLP::bdlbb; BlobUtil; true; getContiguousRangeOrCopy; ; ; Argument[*1]; ReturnValue[*]; taint; manual | +| 108 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:56 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | recv_buffer | provenance | Src:MaD:56 Sink:MaD:4 | @@ -111,16 +115,16 @@ edges | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | send_buffer | provenance | Sink:MaD:4 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:104 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:108 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | | azure.cpp:253:48:253:60 | call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:53 | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:93 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:97 | | azure.cpp:257:16:257:21 | Read output argument | azure.cpp:258:10:258:16 | * ... | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:94 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:98 | | azure.cpp:262:23:262:28 | ReadToCount output argument | azure.cpp:263:10:263:16 | * ... | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:95 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:99 | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | | | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | azure.cpp:267:10:267:12 | vec [element] | provenance | | | azure.cpp:267:10:267:12 | vec [element] | azure.cpp:267:10:267:12 | vec | provenance | | @@ -136,10 +140,10 @@ edges | azure.cpp:278:10:278:13 | body | azure.cpp:278:10:278:13 | body | provenance | | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | | azure.cpp:281:68:281:84 | call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:50 | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:95 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:99 | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:10:282:38 | call to ReadToEnd | provenance | | | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:96 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:100 | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:24:289:56 | call to GetHeader | provenance | | | azure.cpp:289:32:289:40 | call to GetHeader | azure.cpp:289:32:289:40 | call to GetHeader | provenance | Src:MaD:54 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | @@ -153,36 +157,36 @@ edges | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | | bdlbb.cpp:54:16:54:23 | call to source | bdlbb.cpp:56:49:56:52 | *call to data | provenance | TaintFunction | | bdlbb.cpp:56:37:56:41 | copy output argument | bdlbb.cpp:58:42:58:45 | *blob | provenance | | -| bdlbb.cpp:56:49:56:52 | *call to data | bdlbb.cpp:56:37:56:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:56:49:56:52 | *call to data | bdlbb.cpp:56:37:56:41 | copy output argument | provenance | MaD:105 | | bdlbb.cpp:58:37:58:39 | copy output argument | bdlbb.cpp:59:7:59:10 | * ... | provenance | | -| bdlbb.cpp:58:42:58:45 | *blob | bdlbb.cpp:58:37:58:39 | copy output argument | provenance | MaD:102 | +| bdlbb.cpp:58:42:58:45 | *blob | bdlbb.cpp:58:37:58:39 | copy output argument | provenance | MaD:106 | | bdlbb.cpp:63:16:63:23 | call to source | bdlbb.cpp:65:49:65:52 | *call to data | provenance | TaintFunction | | bdlbb.cpp:65:37:65:41 | copy output argument | bdlbb.cpp:66:18:66:21 | *blob | provenance | | -| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | provenance | MaD:101 | -| bdlbb.cpp:66:18:66:21 | *blob | bdlbb.cpp:66:29:66:32 | *call to buffer | provenance | MaD:97 | +| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | provenance | MaD:105 | +| bdlbb.cpp:66:18:66:21 | *blob | bdlbb.cpp:66:29:66:32 | *call to buffer | provenance | MaD:101 | | bdlbb.cpp:66:18:66:38 | *call to data | bdlbb.cpp:66:18:66:38 | *call to data | provenance | | | bdlbb.cpp:66:18:66:38 | *call to data | bdlbb.cpp:67:7:67:8 | * ... | provenance | | -| bdlbb.cpp:66:29:66:32 | *call to buffer | bdlbb.cpp:66:18:66:38 | *call to data | provenance | MaD:99 | +| bdlbb.cpp:66:29:66:32 | *call to buffer | bdlbb.cpp:66:18:66:38 | *call to data | provenance | MaD:103 | | bdlbb.cpp:72:16:72:23 | call to source | bdlbb.cpp:74:49:74:52 | *call to data | provenance | TaintFunction | | bdlbb.cpp:74:37:74:41 | copy output argument | bdlbb.cpp:75:18:75:21 | *blob | provenance | | -| bdlbb.cpp:74:49:74:52 | *call to data | bdlbb.cpp:74:37:74:41 | copy output argument | provenance | MaD:101 | -| bdlbb.cpp:75:18:75:21 | *blob | bdlbb.cpp:75:29:75:32 | *call to buffer | provenance | MaD:97 | +| bdlbb.cpp:74:49:74:52 | *call to data | bdlbb.cpp:74:37:74:41 | copy output argument | provenance | MaD:105 | +| bdlbb.cpp:75:18:75:21 | *blob | bdlbb.cpp:75:29:75:32 | *call to buffer | provenance | MaD:101 | | bdlbb.cpp:75:18:75:46 | call to get | bdlbb.cpp:76:7:76:8 | * ... | provenance | | -| bdlbb.cpp:75:29:75:32 | *call to buffer | bdlbb.cpp:75:39:75:41 | *call to buffer | provenance | MaD:98 | +| bdlbb.cpp:75:29:75:32 | *call to buffer | bdlbb.cpp:75:39:75:41 | *call to buffer | provenance | MaD:102 | | bdlbb.cpp:75:39:75:41 | *call to buffer | bdlbb.cpp:75:18:75:46 | call to get | provenance | DataFlowFunction | | bdlbb.cpp:80:16:80:23 | call to source | bdlbb.cpp:82:49:82:52 | *call to data | provenance | TaintFunction | | bdlbb.cpp:82:37:82:41 | copy output argument | bdlbb.cpp:84:72:84:75 | *blob | provenance | | -| bdlbb.cpp:82:49:82:52 | *call to data | bdlbb.cpp:82:37:82:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:82:49:82:52 | *call to data | bdlbb.cpp:82:37:82:41 | copy output argument | provenance | MaD:105 | | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | provenance | | | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:85:7:85:8 | * ... | provenance | | -| bdlbb.cpp:84:72:84:75 | *blob | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | provenance | MaD:103 | +| bdlbb.cpp:84:72:84:75 | *blob | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | provenance | MaD:107 | | bdlbb.cpp:90:16:90:23 | call to source | bdlbb.cpp:92:48:92:51 | *call to data | provenance | TaintFunction | | bdlbb.cpp:92:37:92:40 | copy output argument | bdlbb.cpp:94:46:94:48 | *src | provenance | | -| bdlbb.cpp:92:48:92:51 | *call to data | bdlbb.cpp:92:37:92:40 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:92:48:92:51 | *call to data | bdlbb.cpp:92:37:92:40 | copy output argument | provenance | MaD:105 | | bdlbb.cpp:94:37:94:40 | copy output argument | bdlbb.cpp:96:42:96:44 | *dst | provenance | | -| bdlbb.cpp:94:46:94:48 | *src | bdlbb.cpp:94:37:94:40 | copy output argument | provenance | MaD:100 | +| bdlbb.cpp:94:46:94:48 | *src | bdlbb.cpp:94:37:94:40 | copy output argument | provenance | MaD:104 | | bdlbb.cpp:96:37:96:39 | copy output argument | bdlbb.cpp:97:7:97:10 | * ... | provenance | | -| bdlbb.cpp:96:42:96:44 | *dst | bdlbb.cpp:96:37:96:39 | copy output argument | provenance | MaD:102 | +| bdlbb.cpp:96:42:96:44 | *dst | bdlbb.cpp:96:37:96:39 | copy output argument | provenance | MaD:106 | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:48 | @@ -234,27 +238,27 @@ edges | test.cpp:133:10:133:18 | call to ymlSource | test.cpp:134:45:134:45 | x | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:134:13:134:43 | call to templateFunction | provenance | | | test.cpp:134:13:134:43 | call to templateFunction | test.cpp:135:10:135:10 | y | provenance | Sink:MaD:3 | -| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:91 | +| test.cpp:134:45:134:45 | x | test.cpp:134:13:134:43 | call to templateFunction | provenance | MaD:95 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:146:10:146:18 | call to ymlSource | provenance | Src:MaD:48 | | test.cpp:146:10:146:18 | call to ymlSource | test.cpp:148:26:148:26 | x | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:148:10:148:27 | call to function | provenance | | | test.cpp:148:10:148:27 | call to function | test.cpp:149:10:149:10 | z | provenance | Sink:MaD:3 | -| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:92 | +| test.cpp:148:26:148:26 | x | test.cpp:148:10:148:27 | call to function | provenance | MaD:96 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:155:10:155:18 | call to ymlSource | provenance | Src:MaD:48 | | test.cpp:155:10:155:18 | call to ymlSource | test.cpp:157:26:157:26 | x | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:157:13:157:20 | call to function | provenance | | | test.cpp:157:13:157:20 | call to function | test.cpp:158:10:158:10 | z | provenance | Sink:MaD:3 | -| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:92 | +| test.cpp:157:26:157:26 | x | test.cpp:157:13:157:20 | call to function | provenance | MaD:96 | | test.cpp:164:34:164:34 | x | test.cpp:165:69:165:69 | x | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:164:7:164:7 | *templateFunction3 | provenance | | | test.cpp:165:12:165:64 | call to templateFunction2 | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | | -| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:90 | +| test.cpp:165:69:165:69 | x | test.cpp:165:12:165:64 | call to templateFunction2 | provenance | MaD:94 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:170:10:170:18 | call to ymlSource | provenance | Src:MaD:48 | | test.cpp:170:10:170:18 | call to ymlSource | test.cpp:172:51:172:51 | x | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | | | test.cpp:172:13:172:44 | call to templateFunction3 | test.cpp:173:10:173:10 | y | provenance | Sink:MaD:3 | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | provenance | | -| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:90 | +| test.cpp:172:51:172:51 | x | test.cpp:172:13:172:44 | call to templateFunction3 | provenance | MaD:94 | | test.cpp:186:2:186:2 | *s [post update] [myField] | test.cpp:187:33:187:34 | *& ... [myField] | provenance | | | test.cpp:186:2:186:24 | ... = ... | test.cpp:186:2:186:2 | *s [post update] [myField] | provenance | | | test.cpp:186:14:186:22 | call to ymlSource | test.cpp:186:2:186:24 | ... = ... | provenance | Src:MaD:48 | @@ -268,15 +272,15 @@ edges | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | test.cpp:201:10:201:10 | x | provenance | Sink:MaD:3 | | test.cpp:200:35:200:36 | *& ... [myField] | test.cpp:200:10:200:33 | call to read_field_from_struct_2 | provenance | MaD:83 | | test.cpp:216:3:216:4 | get_ptr output argument [value] | test.cpp:217:11:217:12 | *rf [value] | provenance | | -| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:89 | +| test.cpp:216:3:216:28 | ... = ... | test.cpp:216:3:216:4 | get_ptr output argument [value] | provenance | MaD:93 | | test.cpp:216:18:216:26 | call to ymlSource | test.cpp:216:3:216:28 | ... = ... | provenance | Src:MaD:48 | | test.cpp:217:11:217:12 | *rf [value] | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:217:14:217:18 | value | provenance | | | test.cpp:217:14:217:18 | value | test.cpp:218:11:218:11 | x | provenance | Sink:MaD:3 | | test.cpp:222:3:222:3 | operator[] output argument | test.cpp:223:12:223:12 | *s | provenance | | -| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:88 | +| test.cpp:222:3:222:20 | ... = ... | test.cpp:222:3:222:3 | operator[] output argument | provenance | MaD:92 | | test.cpp:222:10:222:18 | call to ymlSource | test.cpp:222:3:222:20 | ... = ... | provenance | Src:MaD:48 | -| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:87 | +| test.cpp:223:12:223:12 | *s | test.cpp:223:13:223:15 | call to operator[] | provenance | MaD:91 | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:223:13:223:15 | call to operator[] | provenance | | | test.cpp:223:13:223:15 | call to operator[] | test.cpp:224:11:224:11 | c | provenance | Sink:MaD:3 | | test.cpp:242:29:242:29 | *s [value] | test.cpp:243:10:243:10 | *s [value] | provenance | | @@ -351,6 +355,43 @@ edges | test.cpp:329:12:329:16 | value | test.cpp:329:12:329:16 | value | provenance | Sink:MaD:3 | | test.cpp:331:10:331:19 | * ... | test.cpp:331:10:331:19 | * ... | provenance | Sink:MaD:3 | | test.cpp:331:11:331:11 | *s [*pointer] | test.cpp:331:10:331:19 | * ... | provenance | | +| test.cpp:341:30:341:32 | arg | test.cpp:342:5:342:17 | ... = ... | provenance | | +| test.cpp:342:5:342:8 | *this [post update] [s] | test.cpp:341:3:341:22 | *this [Return] [s] | provenance | | +| test.cpp:342:5:342:17 | ... = ... | test.cpp:342:5:342:8 | *this [post update] [s] | provenance | | +| test.cpp:345:38:345:40 | arg | test.cpp:346:5:346:18 | ... = ... | provenance | | +| test.cpp:346:5:346:8 | *this [post update] [ul] | test.cpp:345:3:345:22 | *this [Return] [ul] | provenance | | +| test.cpp:346:5:346:18 | ... = ... | test.cpp:346:5:346:8 | *this [post update] [ul] | provenance | | +| test.cpp:361:15:361:23 | call to ymlSource | test.cpp:361:15:361:25 | call to ymlSource | provenance | Src:MaD:48 | +| test.cpp:361:15:361:25 | call to ymlSource | test.cpp:362:15:362:15 | *x | provenance | | +| test.cpp:362:5:362:5 | forward output argument [s] | test.cpp:364:30:364:30 | *f [s] | provenance | | +| test.cpp:362:15:362:15 | *x | test.cpp:341:30:341:32 | arg | provenance | MaD:89 | +| test.cpp:362:15:362:15 | *x | test.cpp:362:5:362:5 | forward output argument [s] | provenance | MaD:89 | +| test.cpp:364:30:364:30 | *f [s] | test.cpp:364:32:364:34 | call to get [s] | provenance | MaD:90 | +| test.cpp:364:32:364:34 | call to get [s] | test.cpp:364:32:364:34 | call to get [s] | provenance | | +| test.cpp:364:32:364:34 | call to get [s] | test.cpp:365:13:365:13 | *c [s] | provenance | | +| test.cpp:365:13:365:13 | *c [s] | test.cpp:365:13:365:15 | s | provenance | | +| test.cpp:365:13:365:13 | *c [s] | test.cpp:365:15:365:15 | s | provenance | Sink:MaD:3 | +| test.cpp:365:13:365:15 | s | test.cpp:365:15:365:15 | s | provenance | Sink:MaD:3 | +| test.cpp:370:24:370:32 | call to ymlSource | test.cpp:370:24:370:34 | call to ymlSource | provenance | Src:MaD:48 | +| test.cpp:370:24:370:34 | call to ymlSource | test.cpp:371:15:371:16 | *ul | provenance | | +| test.cpp:371:5:371:5 | forward output argument [ul] | test.cpp:373:30:373:30 | *f [ul] | provenance | | +| test.cpp:371:15:371:16 | *ul | test.cpp:345:38:345:40 | arg | provenance | MaD:89 | +| test.cpp:371:15:371:16 | *ul | test.cpp:371:5:371:5 | forward output argument [ul] | provenance | MaD:89 | +| test.cpp:373:30:373:30 | *f [ul] | test.cpp:373:32:373:34 | call to get [ul] | provenance | MaD:90 | +| test.cpp:373:32:373:34 | call to get [ul] | test.cpp:373:32:373:34 | call to get [ul] | provenance | | +| test.cpp:373:32:373:34 | call to get [ul] | test.cpp:375:13:375:13 | *c [ul] | provenance | | +| test.cpp:375:13:375:13 | *c [ul] | test.cpp:375:13:375:16 | ul | provenance | | +| test.cpp:375:13:375:13 | *c [ul] | test.cpp:375:15:375:16 | ul | provenance | Sink:MaD:3 | +| test.cpp:375:13:375:16 | ul | test.cpp:375:15:375:16 | ul | provenance | Sink:MaD:3 | +| test.cpp:394:11:394:19 | call to ymlSource | test.cpp:394:11:394:19 | call to ymlSource | provenance | Src:MaD:48 | +| test.cpp:394:11:394:19 | call to ymlSource | test.cpp:395:13:395:13 | *x | provenance | | +| test.cpp:395:3:395:3 | emplace output argument [element, x] | test.cpp:397:15:397:15 | *c [element, x] | provenance | | +| test.cpp:395:13:395:13 | *x | test.cpp:395:3:395:3 | emplace output argument [element, x] | provenance | MaD:87 | +| test.cpp:397:15:397:15 | *c [element, x] | test.cpp:397:20:397:22 | call to get [x] | provenance | MaD:88 | +| test.cpp:397:20:397:22 | call to get [x] | test.cpp:397:20:397:22 | call to get [x] | provenance | | +| test.cpp:397:20:397:22 | call to get [x] | test.cpp:398:11:398:11 | *e [x] | provenance | | +| test.cpp:398:11:398:11 | *e [x] | test.cpp:398:13:398:13 | x | provenance | | +| test.cpp:398:13:398:13 | x | test.cpp:398:13:398:13 | x | provenance | Sink:MaD:3 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:27:36:27:38 | *cmd | provenance | | | windows.cpp:22:15:22:29 | call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:5 | @@ -811,6 +852,44 @@ nodes | test.cpp:331:10:331:19 | * ... | semmle.label | * ... | | test.cpp:331:11:331:11 | *s [*pointer] | semmle.label | *s [*pointer] | | test.cpp:334:10:334:16 | * ... | semmle.label | * ... | +| test.cpp:341:3:341:22 | *this [Return] [s] | semmle.label | *this [Return] [s] | +| test.cpp:341:30:341:32 | arg | semmle.label | arg | +| test.cpp:342:5:342:8 | *this [post update] [s] | semmle.label | *this [post update] [s] | +| test.cpp:342:5:342:17 | ... = ... | semmle.label | ... = ... | +| test.cpp:345:3:345:22 | *this [Return] [ul] | semmle.label | *this [Return] [ul] | +| test.cpp:345:38:345:40 | arg | semmle.label | arg | +| test.cpp:346:5:346:8 | *this [post update] [ul] | semmle.label | *this [post update] [ul] | +| test.cpp:346:5:346:18 | ... = ... | semmle.label | ... = ... | +| test.cpp:361:15:361:23 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:361:15:361:25 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:362:5:362:5 | forward output argument [s] | semmle.label | forward output argument [s] | +| test.cpp:362:15:362:15 | *x | semmle.label | *x | +| test.cpp:364:30:364:30 | *f [s] | semmle.label | *f [s] | +| test.cpp:364:32:364:34 | call to get [s] | semmle.label | call to get [s] | +| test.cpp:364:32:364:34 | call to get [s] | semmle.label | call to get [s] | +| test.cpp:365:13:365:13 | *c [s] | semmle.label | *c [s] | +| test.cpp:365:13:365:15 | s | semmle.label | s | +| test.cpp:365:15:365:15 | s | semmle.label | s | +| test.cpp:370:24:370:32 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:370:24:370:34 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:371:5:371:5 | forward output argument [ul] | semmle.label | forward output argument [ul] | +| test.cpp:371:15:371:16 | *ul | semmle.label | *ul | +| test.cpp:373:30:373:30 | *f [ul] | semmle.label | *f [ul] | +| test.cpp:373:32:373:34 | call to get [ul] | semmle.label | call to get [ul] | +| test.cpp:373:32:373:34 | call to get [ul] | semmle.label | call to get [ul] | +| test.cpp:375:13:375:13 | *c [ul] | semmle.label | *c [ul] | +| test.cpp:375:13:375:16 | ul | semmle.label | ul | +| test.cpp:375:15:375:16 | ul | semmle.label | ul | +| test.cpp:394:11:394:19 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:394:11:394:19 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:395:3:395:3 | emplace output argument [element, x] | semmle.label | emplace output argument [element, x] | +| test.cpp:395:13:395:13 | *x | semmle.label | *x | +| test.cpp:397:15:397:15 | *c [element, x] | semmle.label | *c [element, x] | +| test.cpp:397:20:397:22 | call to get [x] | semmle.label | call to get [x] | +| test.cpp:397:20:397:22 | call to get [x] | semmle.label | call to get [x] | +| test.cpp:398:11:398:11 | *e [x] | semmle.label | *e [x] | +| test.cpp:398:13:398:13 | x | semmle.label | x | +| test.cpp:398:13:398:13 | x | semmle.label | x | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA | | windows.cpp:22:15:22:29 | call to GetCommandLineA | semmle.label | call to GetCommandLineA | | windows.cpp:24:8:24:11 | * ... | semmle.label | * ... | @@ -1032,4 +1111,6 @@ nodes subpaths | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | | test.cpp:172:51:172:51 | x | test.cpp:164:34:164:34 | x | test.cpp:164:7:164:7 | *templateFunction3 | test.cpp:172:13:172:44 | call to templateFunction3 | +| test.cpp:362:15:362:15 | *x | test.cpp:341:30:341:32 | arg | test.cpp:341:3:341:22 | *this [Return] [s] | test.cpp:362:5:362:5 | forward output argument [s] | +| test.cpp:371:15:371:16 | *ul | test.cpp:345:38:345:40 | arg | test.cpp:345:3:345:22 | *this [Return] [ul] | test.cpp:371:5:371:5 | forward output argument [ul] | testFailures diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml b/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml index 0db87b5da615..b501e361b1e6 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml @@ -42,3 +42,16 @@ extensions: - ["", "ReverseFlow", True, "get_ptr", "", "", "ReturnValue[*]", "Argument[-1].Field[ReverseFlow::value]", "value", "manual"] - ["", "MyString", True, "operator[]", "", "", "ReturnValue[*]", "Argument[-1]", "taint", "manual"] - ["", "MyString", True, "operator[]", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + - ["", "Forwarder", True, "forward", "", "", "Argument[*0]", "Argument[forward].Parameter[0]", "value", "manual"] + - ["", "Forwarder", True, "forward", "", "", "Argument[forward].Parameter[-1]", "Argument[-1]", "value", "manual"] + - ["", "Forwarder", True, "get", "", "", "Argument[-1]", "ReturnValue", "value", "manual"] + - ["", "Container", True, "emplace", "", "", "Argument[*0]", "Argument[forward].Parameter[0]", "value", "manual"] + - ["", "Container", True, "emplace", "", "", "Argument[forward].Parameter[-1]", "Argument[-1].Element", "value", "manual"] + - ["", "Container", True, "get", "", "", "Argument[-1].Element", "ReturnValue[*]", "value", "manual"] + - ["", "Element", True, "Element", "", "", "Argument[0]", "Argument[-1].Field[Element::x]", "value", "manual"] + - addsTo: + pack: codeql/cpp-all + extensible: forwardsModel + data: # namespace, type, subtypes, name, signature, ext, start, constructor, provenance + - ["", "Forwarder", True, "forward", "(Args &&)", "", "0", "T", "manual"] + - ["", "Container", True, "emplace", "(Args &&)", "", "0", "T", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected index 5851e825013d..76acdaebbf32 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected @@ -43,3 +43,8 @@ | test.cpp:331:10:331:19 | * ... | test-sink | | test.cpp:333:15:333:20 | source | test-sink | | test.cpp:334:10:334:16 | * ... | test-sink | +| test.cpp:365:15:365:15 | s | test-sink | +| test.cpp:366:15:366:16 | ul | test-sink | +| test.cpp:374:15:374:15 | s | test-sink | +| test.cpp:375:15:375:16 | ul | test-sink | +| test.cpp:398:13:398:13 | x | test-sink | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected index b30f1e88b99a..0d34a8987c1c 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -19,6 +19,9 @@ | test.cpp:222:10:222:18 | call to ymlSource | local | | test.cpp:297:33:297:41 | call to ymlSource | local | | test.cpp:317:51:317:59 | call to ymlSource | local | +| test.cpp:361:15:361:23 | call to ymlSource | local | +| test.cpp:370:24:370:32 | call to ymlSource | local | +| test.cpp:394:11:394:19 | call to ymlSource | local | | windows.cpp:22:15:22:29 | call to GetCommandLineA | local | | windows.cpp:34:17:34:38 | call to GetEnvironmentStringsA | local | | windows.cpp:39:36:39:38 | GetEnvironmentVariableA output argument | local | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp index 739c36bc67d3..8048ea50192e 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp @@ -332,4 +332,68 @@ void test_parameter(SourceWrapper* p, SourceWrapper s, int* source) { ymlSink((int)source); // clean ymlSink(*source); // $ ir +} + + +struct ConstructableFromInt { + short s; + unsigned long ul; + ConstructableFromInt(short arg) { + this->s = arg; + } + + ConstructableFromInt(unsigned long arg) { + this->ul = arg; + } +}; + +template +struct Forwarder { + template + void forward(Args&&... args); + + T get(); +}; + +void forward_test() { + { + Forwarder f; + short x = ymlSource(); + f.forward(x); + + ConstructableFromInt c = f.get(); + ymlSink(c.s); // $ ir + ymlSink(c.ul); // clean + } + { + Forwarder f; + unsigned long ul = ymlSource(); + f.forward(ul); + + ConstructableFromInt c = f.get(); + ymlSink(c.s); // clean + ymlSink(c.ul); // $ ir + } +} + +template +struct Container { + template + void emplace(Args&&... args); + + T& get(); +}; + +struct Element { + int x; + Element(int); +}; + +void forward_test_model() { + Container c; + int x = ymlSource(); + c.emplace(x); + + Element e = c.get(); + ymlSink(e.x); // $ ir } \ No newline at end of file