From 0be36637a469c5cb84efb7aefa727da34f45995d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 7 Sep 2026 17:43:17 +0100 Subject: [PATCH 1/7] C++: Add tests with missing flow. In the upcoming commits we will add a new extensional predicate which allows us to model that a function forwards it arguments to the constructor of a given type. This initial commit adds the test YAML models for this new extensional predicate. --- .../dataflow/external-models/flow.ext.yml | 13 ++++ .../dataflow/external-models/sinks.expected | 4 ++ .../dataflow/external-models/sources.expected | 2 + .../dataflow/external-models/test.cpp | 64 +++++++++++++++++++ 4 files changed, 83 insertions(+) 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..9b67b3325936 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,7 @@ | 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:364:13:364:13 | s | test-sink | +| test.cpp:365:13:365:14 | ul | test-sink | +| test.cpp:373:13:373:13 | s | test-sink | +| test.cpp:374:13:374:14 | ul | 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..4428beda8552 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,8 @@ | 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:360:13:360:21 | call to ymlSource | local | +| test.cpp:369:22:369:30 | 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..377e3e9543b2 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); // $ MISSING: 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); // $ MISSING: 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); // $ MISSING: ir } \ No newline at end of file From 8c8ce6055b116e2fd17afe1e4ae168c3bed0ae7c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 8 Sep 2026 12:52:49 +0100 Subject: [PATCH 2/7] C++: Add a missing utility predicate on Call instructions. --- .../implementation/aliased_ssa/Instruction.qll | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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`. From ecd3cae1c401e5f47bffa4b1d270237d3d932be3 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 8 Sep 2026 12:53:05 +0100 Subject: [PATCH 3/7] C++: Sync identical files. --- .../cpp/ir/implementation/raw/Instruction.qll | 17 +++++++++++++++++ .../unaliased_ssa/Instruction.qll | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) 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`. From 8560e3414892860e45aaa371907541e59b60f7b7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 7 Sep 2026 17:51:57 +0100 Subject: [PATCH 4/7] C++: We will need the template resolution for something other than the signature to implement the forwardsModel. So instead of recursing on the number of elements in the signature we will recurse on the number of elements in the type (or name) columns. For well-formed models this will be equivalent. --- .../semmle/code/cpp/dataflow/ExternalFlow.qll | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index 4f84b30d557e..40cb03daf262 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -596,6 +596,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 +613,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 +627,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 +644,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 +659,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 ) From 5251c65e33d22947b4f785e12880833f755739d2 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 7 Sep 2026 17:58:27 +0100 Subject: [PATCH 5/7] C++: Add MaD support for models that specify argument forwarding. --- cpp/ql/lib/ext/empty.model.yml | 4 ++ .../semmle/code/cpp/dataflow/ExternalFlow.qll | 59 ++++++++++++++++++- .../internal/ExternalFlowExtensions.qll | 8 +++ .../cpp/dataflow/internal/FlowSummaryImpl.qll | 3 + .../ir/dataflow/internal/DataFlowPrivate.qll | 17 ++++++ 5 files changed, 90 insertions(+), 1 deletion(-) 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 40cb03daf262..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, _, _, _, _) } /** @@ -1054,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/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 551035c5589e..5cfcecbbc529 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 @@ -672,6 +672,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 +727,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 +756,7 @@ newtype TPosition = indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(p.getUnspecifiedType()) - 1] ) } or + TForwardPosition() or TFlowSummaryPosition(ReturnKind rk) { FlowSummaryImpl::Private::relevantFlowSummaryPosition(rk) } private newtype TReturnKind = From 70be52a771d17257bea5bf2a0afd95f1e92ddf7e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 8 Sep 2026 12:25:10 +0100 Subject: [PATCH 6/7] C++: Add a synthetic parameter for the lambda for forward functions and implement forwarding. --- .../ir/dataflow/internal/DataFlowNodes.qll | 3 + .../ir/dataflow/internal/DataFlowPrivate.qll | 116 +++++++++++++++--- 2 files changed, 105 insertions(+), 14 deletions(-) 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 5cfcecbbc529..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. @@ -1275,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. @@ -1310,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()) } /** @@ -1510,6 +1593,8 @@ predicate nodeIsHidden(Node n) { n instanceof SsaSynthNode or n.(FlowSummaryNode).getSummaryNode().isHidden() + or + n instanceof ForwarderConstructorArgumentNode } predicate neverSkipInPathGraph(Node n) { @@ -1591,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) From 232b29ee8beedf75af68c7fefc314156bdab17d7 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Mon, 7 Sep 2026 20:14:15 +0100 Subject: [PATCH 7/7] C++: Accept test changes. --- .../dataflow/external-models/flow.expected | 171 +++++++++++++----- .../dataflow/external-models/sinks.expected | 9 +- .../dataflow/external-models/sources.expected | 5 +- .../dataflow/external-models/test.cpp | 6 +- 4 files changed, 137 insertions(+), 54 deletions(-) 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/sinks.expected b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected index 9b67b3325936..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,7 +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:364:13:364:13 | s | test-sink | -| test.cpp:365:13:365:14 | ul | test-sink | -| test.cpp:373:13:373:13 | s | test-sink | -| test.cpp:374:13:374:14 | ul | 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 4428beda8552..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,8 +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:360:13:360:21 | call to ymlSource | local | -| test.cpp:369:22:369:30 | 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 377e3e9543b2..8048ea50192e 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp @@ -362,7 +362,7 @@ void forward_test() { f.forward(x); ConstructableFromInt c = f.get(); - ymlSink(c.s); // $ MISSING: ir + ymlSink(c.s); // $ ir ymlSink(c.ul); // clean } { @@ -372,7 +372,7 @@ void forward_test() { ConstructableFromInt c = f.get(); ymlSink(c.s); // clean - ymlSink(c.ul); // $ MISSING: ir + ymlSink(c.ul); // $ ir } } @@ -395,5 +395,5 @@ void forward_test_model() { c.emplace(x); Element e = c.get(); - ymlSink(e.x); // $ MISSING: ir + ymlSink(e.x); // $ ir } \ No newline at end of file