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 d776985720af..d7f26dd00513 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 @@ -1382,16 +1382,89 @@ predicate neverSkipInPathGraph(Node n) { exists(n.asIndirectDefinition()) } -class LambdaCallKind = Unit; +private newtype TLambdaCallKind = + TFunctionPointer() or + TFunctor() + +class LambdaCallKind extends TLambdaCallKind { + predicate isFunctionPointer() { this = TFunctionPointer() } + + predicate isFunctor() { this = TFunctor() } + + string toString() { + this.isFunctionPointer() and + result = "Function pointer kind" + or + this.isFunctor() and + result = "Functor kind" + } +} + +private class ConstructorCallInstruction extends CallInstruction { + Cpp::Class constructedType; + + ConstructorCallInstruction() { + this.getStaticCallTarget().(Cpp::Constructor).getDeclaringType() = constructedType + } + + Cpp::Class getConstructedType() { result = constructedType } +} + +private class OperatorCall extends Cpp::MemberFunction { + OperatorCall() { this.hasName("operator()") } +} + +private predicate isFunctorCreationWithoutConstructor(Node creation, OperatorCall operator) { + exists(UninitializedInstruction init, Instruction dest | + // A construction of an object with no constructor. In this case we use + // the `UninitializedInstruction` as the creation node. + init = creation.asInstruction() and + dest = init.getDestinationAddress() and + not any(ConstructorCallInstruction constructorCall).getThisArgument() = dest and + operator.getDeclaringType() = init.getResultType() + ) + or + // Workaround for an extractor bug. In this snippet: + // ``` + // struct S { }; + // void f(S); + // f(S()); + // ``` + // The expression `S()` is represented as a 0 literal in the database. + exists(ConstantValueInstruction constant | + constant.getValue() = "0" and + creation.asInstruction() = constant and + constant.getResultType() = operator.getDeclaringType() + ) +} + +private predicate isFunctorCreationWithConstructor(Node creation, OperatorCall operator) { + exists(DataFlowCall constructorCall, IndirectionPosition pos | + // A construction of an object with a constructor. In this case we use + // the post-update node of the qualifier + pos.getArgumentIndex() = -1 and + isArgumentNode(creation.(PostUpdateNode).getPreUpdateNode(), constructorCall, pos) and + operator.getDeclaringType() = + constructorCall.asCallInstruction().(ConstructorCallInstruction).getConstructedType() + ) +} /** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) { - creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable() and - exists(kind) + kind.isFunctionPointer() and + creation.asInstruction().(FunctionAddressInstruction).getFunctionSymbol() = c.asSourceCallable() + or + kind.isFunctor() and + exists(OperatorCall operator | operator = c.asSourceCallable() | + isFunctorCreationWithoutConstructor(creation, operator) + or + isFunctorCreationWithConstructor(creation, operator) + ) } /** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { + kind.isFunctionPointer() and ( call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() or @@ -1400,8 +1473,15 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { // has a result for `getStaticCallTarget`. not exists(call.getStaticCallTarget()) and call.asCallInstruction().getCallTargetOperand() = receiver.asOperand() - ) and - exists(kind) + ) + or + kind.isFunctor() and + ( + call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() + or + not exists(call.getStaticCallTarget()) and + call.asCallInstruction().getThisArgumentOperand() = receiver.asOperand() + ) } /** Extra data-flow steps needed for lambda flow analysis. */ 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 af5dd4199858..96c18a04ff7b 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 @@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction { * Gets the variable that is uninitialized. */ final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } + + /** + * Gets the operand that provides the address of the location to which the + * uninitialized value will be stored. + */ + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the location to + * which the value will be stored, if an exact definition is available. + */ + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } } /** 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 af5dd4199858..96c18a04ff7b 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 @@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction { * Gets the variable that is uninitialized. */ final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } + + /** + * Gets the operand that provides the address of the location to which the + * uninitialized value will be stored. + */ + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the location to + * which the value will be stored, if an exact definition is available. + */ + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } } /** 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 af5dd4199858..96c18a04ff7b 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 @@ -725,6 +725,20 @@ class UninitializedInstruction extends VariableInstruction { * Gets the variable that is uninitialized. */ final Language::Variable getLocalVariable() { result = var.(IRUserVariable).getVariable() } + + /** + * Gets the operand that provides the address of the location to which the + * uninitialized value will be stored. + */ + final AddressOperand getDestinationAddressOperand() { result = this.getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the location to + * which the value will be stored, if an exact definition is available. + */ + final Instruction getDestinationAddress() { + result = this.getDestinationAddressOperand().getDef() + } } /** diff --git a/cpp/ql/src/change-notes/2025-07-11-function-objects.md b/cpp/ql/src/change-notes/2025-07-11-function-objects.md new file mode 100644 index 000000000000..48bc71f27ca8 --- /dev/null +++ b/cpp/ql/src/change-notes/2025-07-11-function-objects.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Improved support for dataflow through function objects and lambda expressions. \ No newline at end of file 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 bf306c28a99d..bf9a4ed28d01 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -21,13 +21,14 @@ models | 20 | Summary: ; ; false; CreateRemoteThreadEx; ; ; Argument[@4]; Argument[3].Parameter[@0]; value; manual | | 21 | Summary: ; ; false; CreateThread; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | | 22 | Summary: ; ; false; ReadFileEx; ; ; Argument[*3].Field[@hEvent]; Argument[4].Parameter[*2].Field[@hEvent]; value; manual | -| 23 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | -| 24 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | -| 25 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | -| 26 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 27 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 23 | Summary: ; ; false; callWithArgument; ; ; Argument[1]; Argument[0].Parameter[0]; value; manual | +| 24 | Summary: ; ; false; pthread_create; ; ; Argument[@3]; Argument[2].Parameter[@0]; value; manual | +| 25 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | +| 26 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | +| 27 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | +| 28 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges -| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:27 | +| asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | asio_streams.cpp:56:18:56:23 | [summary] to write: ReturnValue in buffer | provenance | MaD:28 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:17 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:17 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | @@ -36,10 +37,10 @@ edges | 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:2 | | asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:56:18:56:23 | [summary param] *0 in buffer | provenance | | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:27 | -| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:25 | -| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:24 | -| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:26 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:28 | +| test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | test.cpp:4:5:4:17 | [summary] to write: ReturnValue in ymlStepManual | provenance | MaD:26 | +| test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | test.cpp:5:5:5:20 | [summary] to write: ReturnValue in ymlStepGenerated | provenance | MaD:25 | +| test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | test.cpp:6:5:6:27 | [summary] to write: ReturnValue in ymlStepManual_with_body | provenance | MaD:27 | | 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:16 | @@ -51,15 +52,15 @@ edges | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | | | test.cpp:17:10:17:22 | call to ymlStepManual | test.cpp:18:10:18:10 | y | provenance | Sink:MaD:1 | | test.cpp:17:24:17:24 | x | test.cpp:4:5:4:17 | [summary param] 0 in ymlStepManual | provenance | | -| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:25 | +| test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | provenance | MaD:26 | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | | | test.cpp:21:10:21:25 | call to ymlStepGenerated | test.cpp:22:10:22:10 | z | provenance | Sink:MaD:1 | | test.cpp:21:27:21:27 | x | test.cpp:5:5:5:20 | [summary param] 0 in ymlStepGenerated | provenance | | -| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:24 | +| test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | provenance | MaD:25 | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | | | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | test.cpp:26:10:26:11 | y2 | provenance | Sink:MaD:1 | | test.cpp:25:35:25:35 | x | test.cpp:6:5:6:27 | [summary param] 0 in ymlStepManual_with_body | provenance | | -| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:26 | +| test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | provenance | MaD:27 | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | provenance | | | test.cpp:32:11:32:36 | call to ymlStepGenerated_with_body | test.cpp:33:10:33:11 | z2 | provenance | Sink:MaD:1 | | test.cpp:32:41:32:41 | x | test.cpp:7:47:7:52 | value2 | provenance | | @@ -67,12 +68,33 @@ edges | test.cpp:46:30:46:32 | *arg [x] | test.cpp:47:12:47:19 | *arg [x] | provenance | | | test.cpp:47:12:47:19 | *arg [x] | test.cpp:48:13:48:13 | *s [x] | provenance | | | test.cpp:48:13:48:13 | *s [x] | test.cpp:48:16:48:16 | x | provenance | Sink:MaD:1 | -| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:23 | +| test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | provenance | MaD:24 | | test.cpp:52:5:52:18 | [summary] to write: Argument[2].Parameter[*0] in pthread_create [x] | test.cpp:46:30:46:32 | *arg [x] | provenance | | | test.cpp:56:2:56:2 | *s [post update] [x] | test.cpp:59:55:59:64 | *& ... [x] | provenance | | | test.cpp:56:2:56:18 | ... = ... | test.cpp:56:2:56:2 | *s [post update] [x] | provenance | | | test.cpp:56:8:56:16 | call to ymlSource | test.cpp:56:2:56:18 | ... = ... | provenance | Src:MaD:16 | | test.cpp:59:55:59:64 | *& ... [x] | test.cpp:52:5:52:18 | [summary param] *3 in pthread_create [x] | provenance | | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:23 | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:23 | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:23 | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | provenance | MaD:23 | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:68:22:68:22 | y | provenance | | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:74:22:74:22 | y | provenance | | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:82:22:82:22 | y | provenance | | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | test.cpp:88:22:88:22 | y | provenance | | +| test.cpp:68:22:68:22 | y | test.cpp:69:11:69:11 | y | provenance | Sink:MaD:1 | +| test.cpp:74:22:74:22 | y | test.cpp:75:11:75:11 | y | provenance | Sink:MaD:1 | +| test.cpp:82:22:82:22 | y | test.cpp:83:11:83:11 | y | provenance | Sink:MaD:1 | +| test.cpp:88:22:88:22 | y | test.cpp:89:11:89:11 | y | provenance | Sink:MaD:1 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:94:10:94:18 | call to ymlSource | provenance | Src:MaD:16 | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:97:26:97:26 | x | provenance | | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:101:26:101:26 | x | provenance | | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:103:63:103:63 | x | provenance | | +| test.cpp:94:10:94:18 | call to ymlSource | test.cpp:104:62:104:62 | x | provenance | | +| test.cpp:97:26:97:26 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | | +| test.cpp:101:26:101:26 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | | +| test.cpp:103:63:103:63 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | | +| test.cpp:104:62:104:62 | x | test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | provenance | | | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | provenance | MaD:18 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:22:15:22:29 | *call to GetCommandLineA | provenance | Src:MaD:3 | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | windows.cpp:24:8:24:11 | * ... | provenance | | @@ -209,6 +231,28 @@ nodes | test.cpp:56:2:56:18 | ... = ... | semmle.label | ... = ... | | test.cpp:56:8:56:16 | call to ymlSource | semmle.label | call to ymlSource | | test.cpp:59:55:59:64 | *& ... [x] | semmle.label | *& ... [x] | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | semmle.label | [summary param] 1 in callWithArgument | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | semmle.label | [summary param] 1 in callWithArgument | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | semmle.label | [summary param] 1 in callWithArgument | +| test.cpp:63:6:63:21 | [summary param] 1 in callWithArgument | semmle.label | [summary param] 1 in callWithArgument | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | semmle.label | [summary] to write: Argument[0].Parameter[0] in callWithArgument | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | semmle.label | [summary] to write: Argument[0].Parameter[0] in callWithArgument | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | semmle.label | [summary] to write: Argument[0].Parameter[0] in callWithArgument | +| test.cpp:63:6:63:21 | [summary] to write: Argument[0].Parameter[0] in callWithArgument | semmle.label | [summary] to write: Argument[0].Parameter[0] in callWithArgument | +| test.cpp:68:22:68:22 | y | semmle.label | y | +| test.cpp:69:11:69:11 | y | semmle.label | y | +| test.cpp:74:22:74:22 | y | semmle.label | y | +| test.cpp:75:11:75:11 | y | semmle.label | y | +| test.cpp:82:22:82:22 | y | semmle.label | y | +| test.cpp:83:11:83:11 | y | semmle.label | y | +| test.cpp:88:22:88:22 | y | semmle.label | y | +| test.cpp:89:11:89:11 | y | semmle.label | y | +| test.cpp:94:10:94:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:94:10:94:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:97:26:97:26 | x | semmle.label | x | +| test.cpp:101:26:101:26 | x | semmle.label | x | +| test.cpp:103:63:103:63 | x | semmle.label | x | +| test.cpp:104:62:104:62 | x | semmle.label | x | | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | semmle.label | [summary param] *0 in CommandLineToArgvA | | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | semmle.label | [summary] to write: ReturnValue[**] in CommandLineToArgvA | | windows.cpp:22:15:22:29 | *call to GetCommandLineA | semmle.label | *call to GetCommandLineA | 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 12dbf7d4cd23..f0df3e749e69 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 @@ -16,4 +16,5 @@ extensions: - ["", "", False, "ymlStepManual", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["", "", False, "ymlStepGenerated", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] - ["", "", False, "ymlStepManual_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - - ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] \ No newline at end of file + - ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] + - ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"] \ No newline at end of file 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 7e5b714765bd..0cc01c8165e1 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected @@ -9,3 +9,7 @@ | test.cpp:33:10:33:11 | z2 | test-sink | | test.cpp:36:10:36:11 | z3 | test-sink | | test.cpp:48:16:48:16 | x | test-sink | +| test.cpp:69:11:69:11 | y | test-sink | +| test.cpp:75:11:75:11 | y | test-sink | +| test.cpp:83:11:83:11 | y | test-sink | +| test.cpp:89:11:89:11 | y | 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 b0f52caf00ca..401fffdbd594 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -1,6 +1,7 @@ | asio_streams.cpp:87:34:87:44 | read_until output argument | remote | | test.cpp:10:10:10:18 | call to ymlSource | local | | test.cpp:56:8:56:16 | call to ymlSource | local | +| test.cpp:94:10:94:18 | 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 d40ee556a63f..f357b934b2fb 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp @@ -58,3 +58,48 @@ int test_pthread_create() { pthread_t threadId; pthread_create(&threadId, nullptr, myThreadFunction, (void *)&s); } + +template +void callWithArgument(F f, int x); + +struct StructWithOperatorCall_has_constructor { + StructWithOperatorCall_has_constructor(); + + void operator()(int y) { + ymlSink(y); // $ ir + } +}; + +struct StructWithOperatorCall_no_constructor { + void operator()(int y) { + ymlSink(y); // $ ir + } +}; + +struct StructWithOperatorCall_has_constructor_2 { + StructWithOperatorCall_has_constructor_2(); + + void operator()(int y) { + ymlSink(y); // $ ir + } +}; + +struct StructWithOperatorCall_no_constructor_2 { + void operator()(int y) { + ymlSink(y); // $ ir + } +}; + +void test_callWithArgument() { + int x = ymlSource(); + { + StructWithOperatorCall_has_constructor func; + callWithArgument(func, x); + } + { + StructWithOperatorCall_no_constructor func; + callWithArgument(func, x); + } + callWithArgument(StructWithOperatorCall_has_constructor_2(), x); + callWithArgument(StructWithOperatorCall_no_constructor_2(), x); +} \ No newline at end of file diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index 1bf719e630ee..e19f34eb2170 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -7777,17 +7777,24 @@ WARNING: module 'TaintTracking' has been deprecated and may be removed in future | thread.cpp:24:5:24:5 | s | thread.cpp:26:38:26:38 | s | | | thread.cpp:24:5:24:5 | s | thread.cpp:27:37:27:37 | s | | | thread.cpp:24:5:24:5 | s | thread.cpp:28:38:28:38 | s | | +| thread.cpp:24:5:24:5 | s | thread.cpp:32:7:32:7 | s | | | thread.cpp:25:3:25:3 | s [post update] | thread.cpp:26:38:26:38 | s | | | thread.cpp:25:3:25:3 | s [post update] | thread.cpp:27:37:27:37 | s | | | thread.cpp:25:3:25:3 | s [post update] | thread.cpp:28:38:28:38 | s | | +| thread.cpp:25:3:25:3 | s [post update] | thread.cpp:32:7:32:7 | s | | | thread.cpp:25:3:25:16 | ... = ... | thread.cpp:25:5:25:5 | x [post update] | | | thread.cpp:25:9:25:14 | call to source | thread.cpp:25:3:25:16 | ... = ... | | -| thread.cpp:26:18:26:39 | call to thread | thread.cpp:29:1:29:1 | t1 | | +| thread.cpp:26:18:26:39 | call to thread | thread.cpp:33:1:33:1 | t1 | | | thread.cpp:26:38:26:38 | s | thread.cpp:26:37:26:38 | & ... | | -| thread.cpp:27:18:27:38 | call to thread | thread.cpp:29:1:29:1 | t2 | | +| thread.cpp:27:18:27:38 | call to thread | thread.cpp:33:1:33:1 | t2 | | | thread.cpp:27:37:27:37 | ref arg s | thread.cpp:28:38:28:38 | s | | -| thread.cpp:28:18:28:43 | call to thread | thread.cpp:29:1:29:1 | t3 | | +| thread.cpp:27:37:27:37 | ref arg s | thread.cpp:32:7:32:7 | s | | +| thread.cpp:28:18:28:43 | call to thread | thread.cpp:33:1:33:1 | t3 | | | thread.cpp:28:38:28:38 | s | thread.cpp:28:37:28:38 | & ... | | +| thread.cpp:30:18:32:8 | call to thread | thread.cpp:33:1:33:1 | t4 | | +| thread.cpp:30:24:30:24 | p | thread.cpp:30:24:30:24 | p | | +| thread.cpp:30:24:30:24 | p | thread.cpp:31:10:31:10 | p | | +| thread.cpp:32:7:32:7 | s | thread.cpp:32:6:32:7 | & ... | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected index 9a128a360357..239ed2ec607d 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/test_mad-signatures.expected @@ -46936,6 +46936,8 @@ getParameterTypeName | stl.h:690:12:690:17 | thread | 0 | func:0 && | | stl.h:690:12:690:17 | thread | 0 | func:0 && | | stl.h:690:12:690:17 | thread | 0 | func:0 && | +| stl.h:690:12:690:17 | thread | 0 | func:0 && | +| stl.h:690:12:690:17 | thread | 1 | func:1 && | | stl.h:690:12:690:17 | thread | 1 | func:1 && | | stl.h:690:12:690:17 | thread | 1 | func:1 && | | stl.h:690:12:690:17 | thread | 1 | func:1 && | @@ -47196,6 +47198,11 @@ getParameterTypeName | thread.cpp:14:6:14:22 | thread_function_2 | 0 | S | | thread.cpp:18:6:18:22 | thread_function_3 | 0 | S * | | thread.cpp:18:6:18:22 | thread_function_3 | 1 | int | +| thread.cpp:30:18:30:18 | (unnamed constructor) | 0 | const lambda [] type at line 762, col. 18 & | +| thread.cpp:30:18:30:18 | (unnamed constructor) | 0 | lambda [] type at line 762, col. 18 && | +| thread.cpp:30:18:30:18 | operator= | 0 | const lambda [] type at line 762, col. 18 & | +| thread.cpp:30:20:30:20 | _FUN | 0 | S * | +| thread.cpp:30:20:30:20 | operator() | 0 | S * | | vector.cpp:13:6:13:9 | sink | 0 | int | | vector.cpp:14:27:14:30 | sink | 0 | vector> & | | vector.cpp:14:27:14:30 | sink | 0 | vector> & | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/thread.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/thread.cpp index b0393801a94c..5a39669d1c6e 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/thread.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/thread.cpp @@ -26,4 +26,8 @@ void test_thread() { std::thread t1(thread_function_1, &s); std::thread t2(thread_function_2, s); std::thread t3(thread_function_3, &s, 42); + + std::thread t4([](S* p) { + sink(p->x); // $ ir + }, &s); } \ No newline at end of file pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy