diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index fb2108c2ac58..4a89e91c74ee 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -276,6 +276,45 @@ private predicate isClassConstructedFrom(Class c, Class templateClass) { not c.isConstructedFrom(_) and c = templateClass } +/** Gets the fully templated version of `c`. */ +private Class getFullyTemplatedClassOld(Class c) { + not c.isFromUninstantiatedTemplate(_) and + isClassConstructedFrom(c, result) +} + +private TemplateClass getOriginalClassTemplate(TemplateClass tc) { + result = tc.getOriginalTemplate() + or + not exists(tc.getOriginalTemplate()) and + result = tc +} + +/** Gets the fully templated version of `c`. */ +private Class getFullyTemplatedClassNew(Class c) { + not c.isFromUninstantiatedTemplate(_) and + exists(Class mid | + c.isConstructedFrom(mid) + or + not c.isConstructedFrom(_) and c = mid + | + result = getOriginalClassTemplate(mid) + or + not mid instanceof TemplateClass and mid = result + ) +} + +/** Gets the fully templated version of `c`. */ +private Class getFullyTemplatedClass(Class c) { + // The `Class::getOriginalTemplate` predicate was introduced in CodeQL + // version 2.25.6 and the upgrade script leaves the + // `class_template_generated_from` extensionals empty if the database + // was generated with an older extractor. So we use the old implementation + // if the `class_template_generated_from` extensional is empty. + if class_template_generated_from(_, _) + then result = getFullyTemplatedClassNew(c) + else result = getFullyTemplatedClassOld(c) +} + /** * Holds if `f` is an instantiation of a function template `templateFunc`, or * holds with `f = templateFunc` if `f` is not an instantiation of any function @@ -292,7 +331,7 @@ private predicate isFunctionConstructedFrom(Function f, Function templateFunc) { } /** Gets the fully templated version of `f`. */ -Function getFullyTemplatedFunction(Function f) { +private Function getFullyTemplatedFunctionOld(Function f) { not f.isFromUninstantiatedTemplate(_) and ( exists(Class c, Class templateClass, int i | @@ -306,13 +345,46 @@ Function getFullyTemplatedFunction(Function f) { ) } +private TemplateFunction getOriginalFunctionTemplate(TemplateFunction tf) { + result = tf.getOriginalTemplate() + or + not exists(tf.getOriginalTemplate()) and + result = tf +} + +/** Gets the fully templated version of `f`. */ +private Function getFullyTemplatedFunctionNew(Function f) { + not f.isFromUninstantiatedTemplate(_) and + exists(Function mid | + f.isConstructedFrom(mid) + or + not f.isConstructedFrom(_) and f = mid + | + result = getOriginalFunctionTemplate(mid) + or + not mid instanceof TemplateFunction and mid = result + ) +} + +/** Gets the fully templated version of `f`. */ +Function getFullyTemplatedFunction(Function f) { + // The `Function::getOriginalTemplate` predicate was introduced in CodeQL + // version 2.25.6 and the upgrade script leaves the + // `function_template_generated_from` extensionals empty if the database + // was generated with an older extractor. So we use the old implementation + // if the `function_template_generated_from` extensional is empty. + if function_template_generated_from(_, _) + then result = getFullyTemplatedFunctionNew(f) + else result = getFullyTemplatedFunctionOld(f) +} + /** Prefixes `const` to `s` if `t` is const, or returns `s` otherwise. */ bindingset[s, t] private string withConst(string s, Type t) { if t.isConst() then result = "const " + s else result = s } -/** Prefixes `volatile` to `s` if `t` is const, or returns `s` otherwise. */ +/** Prefixes `volatile` to `s` if `t` is volatile, or returns `s` otherwise. */ bindingset[s, t] private string withVolatile(string s, Type t) { if t.isVolatile() then result = "volatile " + s else result = s @@ -490,7 +562,7 @@ pragma[nomagic] private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) { // If there is a declaring type then we start by expanding the function templates exists(Class template | - isClassConstructedFrom(f.getDeclaringType(), template) and + template = getFullyTemplatedClass(f.getDeclaringType()) and remaining = getNumberOfSupportedClassTemplateArguments(template) and result = getTypeNameWithoutFunctionTemplates(f, n, 0) ) @@ -502,7 +574,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining or exists(string mid, TypeTemplateParameter tp, Class template | mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and - isClassConstructedFrom(f.getDeclaringType(), template) and + template = getFullyTemplatedClass(f.getDeclaringType()) and tp = getSupportedClassTemplateArgument(template, remaining) | result = mid.replaceAll(tp.getName(), "class:" + remaining.toString()) 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 4142b09473a9..2b790a2838b1 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -51,13 +51,15 @@ models | 50 | Summary: ; ; false; ymlStepGenerated; ; ; Argument[0]; ReturnValue; taint; df-generated | | 51 | Summary: ; ; false; ymlStepManual; ; ; Argument[0]; ReturnValue; taint; manual | | 52 | Summary: ; ; false; ymlStepManual_with_body; ; ; Argument[0]; ReturnValue; taint; manual | -| 53 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 54 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | -| 55 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | -| 56 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 57 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 53 | Summary: ; TemplateClass1; false; templateFunction; (T,U); ; Argument[0]; ReturnValue; value; manual | +| 54 | Summary: ; TemplateClass2; false; function; (U,T); ; Argument[1]; ReturnValue; value; manual | +| 55 | Summary: Azure::Core::IO; BodyStream; true; Read; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 56 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | +| 57 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | +| 58 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 59 | 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:57 | +| 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:59 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:32 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | *recv_buffer | provenance | Src:MaD:32 Sink:MaD:2 | | asio_streams.cpp:97:37:97:44 | call to source | asio_streams.cpp:98:7:98:14 | send_str | provenance | TaintFunction | @@ -66,24 +68,24 @@ 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:57 | -| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:56 | -| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:53 | -| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:54 | -| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:55 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:59 | +| azure.cpp:62:10:62:14 | [summary param] this in Value | azure.cpp:62:10:62:14 | [summary] to write: ReturnValue[*] in Value | provenance | MaD:58 | +| azure.cpp:113:16:113:19 | [summary param] this in Read | azure.cpp:113:16:113:19 | [summary param] *0 in Read [Return] | provenance | MaD:55 | +| azure.cpp:114:16:114:26 | [summary param] this in ReadToCount | azure.cpp:114:16:114:26 | [summary param] *0 in ReadToCount [Return] | provenance | MaD:56 | +| azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | provenance | MaD:57 | | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue.Element in ReadToEnd | azure.cpp:115:30:115:38 | [summary] to write: ReturnValue in ReadToEnd [element] | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:253:48:253:60 | *call to GetBodyStream | provenance | Src:MaD:29 | | 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:257:5:257:8 | *resp | azure.cpp:113:16:113:19 | [summary param] this in Read | provenance | | -| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:53 | +| azure.cpp:257:5:257:8 | *resp | azure.cpp:257:16:257:21 | Read output argument | provenance | MaD:55 | | 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:114:16:114:26 | [summary param] this in ReadToCount | provenance | | -| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:54 | +| azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | provenance | MaD:56 | | 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:115:30:115:38 | [summary param] this in ReadToEnd | provenance | | -| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:55 | +| azure.cpp:266:38:266:41 | *resp | azure.cpp:266:44:266:52 | call to ReadToEnd [element] | provenance | MaD:57 | | 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 | | @@ -100,11 +102,11 @@ edges | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | provenance | Src:MaD:26 | | azure.cpp:281:68:281:84 | *call to ExtractBodyStream | azure.cpp:282:21:282:23 | *call to get | provenance | | | azure.cpp:282:21:282:23 | *call to get | azure.cpp:115:30:115:38 | [summary param] this in ReadToEnd | provenance | | -| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:55 | +| azure.cpp:282:21:282:23 | *call to get | azure.cpp:282:28:282:36 | call to ReadToEnd [element] | provenance | MaD:57 | | 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:62:10:62:14 | [summary param] this in Value | provenance | | -| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:56 | +| azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | provenance | MaD:58 | | 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:30 | | azure.cpp:289:63:289:65 | call to Value | azure.cpp:289:63:289:65 | call to Value | provenance | | @@ -180,6 +182,20 @@ edges | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | test.cpp:119:10:119:11 | y2 | provenance | Sink:MaD:1 | | test.cpp:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | provenance | | | test.cpp:118:44:118:44 | *x | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | provenance | MaD:48 | +| test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | provenance | MaD:53 | +| test.cpp:130:10:130:18 | call to ymlSource | test.cpp:130:10:130:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:130:10:130:18 | call to ymlSource | test.cpp:131:45:131:45 | x | provenance | | +| test.cpp:131:13:131:43 | call to templateFunction | test.cpp:131:13:131:43 | call to templateFunction | provenance | | +| test.cpp:131:13:131:43 | call to templateFunction | test.cpp:132:10:132:10 | y | provenance | Sink:MaD:1 | +| test.cpp:131:45:131:45 | x | test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | provenance | | +| test.cpp:131:45:131:45 | x | test.cpp:131:13:131:43 | call to templateFunction | provenance | MaD:53 | +| test.cpp:137:4:137:11 | [summary param] 1 in function | test.cpp:137:4:137:11 | [summary] to write: ReturnValue in function | provenance | MaD:54 | +| test.cpp:143:10:143:18 | call to ymlSource | test.cpp:143:10:143:18 | call to ymlSource | provenance | Src:MaD:25 | +| test.cpp:143:10:143:18 | call to ymlSource | test.cpp:145:26:145:26 | x | provenance | | +| test.cpp:145:10:145:27 | call to function | test.cpp:145:10:145:27 | call to function | provenance | | +| test.cpp:145:10:145:27 | call to function | test.cpp:146:10:146:10 | z | provenance | Sink:MaD:1 | +| test.cpp:145:26:145:26 | x | test.cpp:137:4:137:11 | [summary param] 1 in function | provenance | | +| test.cpp:145:26:145:26 | x | test.cpp:145:10:145:27 | call to function | provenance | MaD:54 | | 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:33 | | 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 | | @@ -483,6 +499,22 @@ nodes | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | semmle.label | call to callWithNonTypeTemplate | | test.cpp:118:44:118:44 | *x | semmle.label | *x | | test.cpp:119:10:119:11 | y2 | semmle.label | y2 | +| test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | semmle.label | [summary param] 0 in templateFunction | +| test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | semmle.label | [summary] to write: ReturnValue in templateFunction | +| test.cpp:130:10:130:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:130:10:130:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:131:13:131:43 | call to templateFunction | semmle.label | call to templateFunction | +| test.cpp:131:13:131:43 | call to templateFunction | semmle.label | call to templateFunction | +| test.cpp:131:45:131:45 | x | semmle.label | x | +| test.cpp:132:10:132:10 | y | semmle.label | y | +| test.cpp:137:4:137:11 | [summary param] 1 in function | semmle.label | [summary param] 1 in function | +| test.cpp:137:4:137:11 | [summary] to write: ReturnValue in function | semmle.label | [summary] to write: ReturnValue in function | +| test.cpp:143:10:143:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:143:10:143:18 | call to ymlSource | semmle.label | call to ymlSource | +| test.cpp:145:10:145:27 | call to function | semmle.label | call to function | +| test.cpp:145:10:145:27 | call to function | semmle.label | call to function | +| test.cpp:145:26:145:26 | x | semmle.label | x | +| test.cpp:146:10:146:10 | z | semmle.label | z | | 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 | @@ -688,6 +720,8 @@ subpaths | test.cpp:25:35:25:35 | x | 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 | test.cpp:25:11:25:33 | call to ymlStepManual_with_body | | 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:118:44:118:44 | *x | test.cpp:111:3:111:25 | [summary param] *0 in callWithNonTypeTemplate | test.cpp:111:3:111:25 | [summary] to write: ReturnValue in callWithNonTypeTemplate | test.cpp:118:11:118:42 | call to callWithNonTypeTemplate | +| test.cpp:131:45:131:45 | x | test.cpp:125:5:125:20 | [summary param] 0 in templateFunction | test.cpp:125:5:125:20 | [summary] to write: ReturnValue in templateFunction | test.cpp:131:13:131:43 | call to templateFunction | +| test.cpp:145:26:145:26 | x | test.cpp:137:4:137:11 | [summary param] 1 in function | test.cpp:137:4:137:11 | [summary] to write: ReturnValue in function | test.cpp:145:10:145:27 | call to function | | windows.cpp:27:36:27:38 | *cmd | windows.cpp:17:8:17:25 | [summary param] *0 in CommandLineToArgvA | windows.cpp:17:8:17:25 | [summary] to write: ReturnValue[**] in CommandLineToArgvA | windows.cpp:27:17:27:34 | **call to CommandLineToArgvA | | windows.cpp:537:40:537:41 | *& ... | windows.cpp:473:17:473:37 | [summary param] *1 in RtlCopyVolatileMemory | windows.cpp:473:17:473:37 | [summary param] *0 in RtlCopyVolatileMemory [Return] | windows.cpp:537:27:537:37 | RtlCopyVolatileMemory output argument | | windows.cpp:542:38:542:39 | *& ... | windows.cpp:479:17:479:35 | [summary param] *1 in RtlCopyDeviceMemory | windows.cpp:479:17:479:35 | [summary param] *0 in RtlCopyDeviceMemory [Return] | windows.cpp:542:25:542:35 | RtlCopyDeviceMemory output argument | 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 8e200aabfbd6..dfa9b981ef1d 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 @@ -18,4 +18,6 @@ extensions: - ["", "", False, "ymlStepManual_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "manual"] - ["", "", False, "ymlStepGenerated_with_body", "", "", "Argument[0]", "ReturnValue", "taint", "df-generated"] - ["", "", False, "callWithArgument", "", "", "Argument[1]", "Argument[0].Parameter[0]", "value", "manual"] - - ["", "", False, "callWithNonTypeTemplate", "(const T &)", "", "Argument[*0]", "ReturnValue", "value", "manual"] \ No newline at end of file + - ["", "", False, "callWithNonTypeTemplate", "(const T &)", "", "Argument[*0]", "ReturnValue", "value", "manual"] + - ["", "TemplateClass1", False, "templateFunction", "(T,U)", "", "Argument[0]", "ReturnValue", "value", "manual"] + - ["", "TemplateClass2", False, "function", "(U,T)", "", "Argument[1]", "ReturnValue", "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 e28349b71590..379ce7238060 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sinks.expected @@ -15,3 +15,5 @@ | test.cpp:89:11:89:11 | y | test-sink | | test.cpp:116:10:116:11 | y1 | test-sink | | test.cpp:119:10:119:11 | y2 | test-sink | +| test.cpp:132:10:132:10 | y | test-sink | +| test.cpp:146:10:146:10 | z | 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 b46aa87af6fe..f13d75bc66b9 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/sources.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/sources.expected @@ -9,6 +9,8 @@ | test.cpp:56:8:56:16 | call to ymlSource | local | | test.cpp:94:10:94:18 | call to ymlSource | local | | test.cpp:114:10:114:18 | call to ymlSource | local | +| test.cpp:130:10:130:18 | call to ymlSource | local | +| test.cpp:143:10:143: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 af11ff958f59..fb9b6ceb0e7b 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/test.cpp +++ b/cpp/ql/test/library-tests/dataflow/external-models/test.cpp @@ -118,3 +118,30 @@ void test_callWithNonTypeTemplate() { int y2 = callWithNonTypeTemplate(x); ymlSink(y2); // $ ir } + +template +struct TemplateClass1 { + template + U templateFunction(T, U); +}; + +void test_template_function_in_template_class() { + TemplateClass1 b; + int x = ymlSource(); + auto y = b.templateFunction(x, 0UL); + ymlSink(y); // $ ir +} + +template +struct TemplateClass2 { + T function(T, S); +}; + +template using PartialInstantiationOfTemplateClass2 = TemplateClass2; + +void test_partial_instantiation() { + int x = ymlSource(); + PartialInstantiationOfTemplateClass2 y; + int z = y.function(0UL, x); + ymlSink(z); // $ ir +} \ No newline at end of file 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 5ad32759da58..d494c09e71d5 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 @@ -27383,54 +27383,55 @@ getParameterTypeName | stl.h:91:24:91:33 | operator++ | 0 | int | | stl.h:95:44:95:44 | back_inserter | 0 | func:0 & | | stl.h:95:44:95:44 | back_inserter | 0 | func:0 & | -| stl.h:148:3:148:14 | basic_string | 0 | const class:2 & | -| stl.h:149:33:149:44 | basic_string | 0 | const class:0 * | -| stl.h:149:33:149:44 | basic_string | 1 | const class:2 & | -| stl.h:151:16:151:20 | c_str | 0 | func:0 | -| stl.h:151:16:151:20 | c_str | 1 | func:0 | -| stl.h:151:16:151:20 | c_str | 2 | const class:2 & | +| stl.h:147:12:147:23 | basic_string | 0 | const class:2 & | +| stl.h:148:3:148:14 | basic_string | 0 | const class:0 * | +| stl.h:148:3:148:14 | basic_string | 1 | const class:2 & | +| stl.h:149:33:149:44 | basic_string | 0 | func:0 | +| stl.h:149:33:149:44 | basic_string | 1 | func:0 | +| stl.h:149:33:149:44 | basic_string | 2 | const class:2 & | +| stl.h:165:8:165:16 | push_back | 0 | class:0 | | stl.h:173:13:173:22 | operator[] | 0 | size_type | | stl.h:175:13:175:14 | at | 0 | size_type | -| stl.h:176:35:176:44 | operator+= | 0 | size_type | -| stl.h:176:35:176:44 | operator+= | 0 | size_type | -| stl.h:177:17:177:26 | operator+= | 0 | const func:0 & | -| stl.h:178:17:178:22 | append | 0 | const class:0 * | -| stl.h:179:17:179:22 | append | 0 | const basic_string & | -| stl.h:180:17:180:22 | append | 0 | const class:0 * | -| stl.h:181:47:181:52 | append | 0 | size_type | -| stl.h:181:47:181:52 | append | 1 | class:0 | -| stl.h:182:17:182:22 | assign | 0 | func:0 | -| stl.h:182:17:182:22 | assign | 1 | func:0 | -| stl.h:183:17:183:22 | assign | 0 | const basic_string & | -| stl.h:184:47:184:52 | assign | 0 | size_type | -| stl.h:184:47:184:52 | assign | 1 | class:0 | -| stl.h:185:17:185:22 | insert | 0 | func:0 | -| stl.h:185:17:185:22 | insert | 1 | func:0 | +| stl.h:176:35:176:44 | operator+= | 0 | const func:0 & | +| stl.h:176:35:176:44 | operator+= | 0 | const func:0 & | +| stl.h:177:17:177:26 | operator+= | 0 | const class:0 * | +| stl.h:178:17:178:22 | append | 0 | const basic_string & | +| stl.h:179:17:179:22 | append | 0 | const class:0 * | +| stl.h:180:17:180:22 | append | 0 | size_type | +| stl.h:180:17:180:22 | append | 1 | class:0 | +| stl.h:181:47:181:52 | append | 0 | func:0 | +| stl.h:181:47:181:52 | append | 1 | func:0 | +| stl.h:182:17:182:22 | assign | 0 | const basic_string & | +| stl.h:183:17:183:22 | assign | 0 | size_type | +| stl.h:183:17:183:22 | assign | 1 | class:0 | +| stl.h:184:47:184:52 | assign | 0 | func:0 | +| stl.h:184:47:184:52 | assign | 1 | func:0 | +| stl.h:185:17:185:22 | insert | 0 | size_type | +| stl.h:185:17:185:22 | insert | 1 | const basic_string & | | stl.h:186:17:186:22 | insert | 0 | size_type | -| stl.h:186:17:186:22 | insert | 1 | const basic_string & | +| stl.h:186:17:186:22 | insert | 1 | size_type | +| stl.h:186:17:186:22 | insert | 2 | class:0 | | stl.h:187:17:187:22 | insert | 0 | size_type | -| stl.h:187:17:187:22 | insert | 1 | size_type | -| stl.h:187:17:187:22 | insert | 2 | class:0 | -| stl.h:188:12:188:17 | insert | 0 | size_type | -| stl.h:188:12:188:17 | insert | 1 | const class:0 * | +| stl.h:187:17:187:22 | insert | 1 | const class:0 * | +| stl.h:188:12:188:17 | insert | 0 | const_iterator | +| stl.h:188:12:188:17 | insert | 1 | size_type | +| stl.h:188:12:188:17 | insert | 2 | class:0 | | stl.h:189:42:189:47 | insert | 0 | const_iterator | -| stl.h:189:42:189:47 | insert | 1 | size_type | -| stl.h:189:42:189:47 | insert | 2 | class:0 | -| stl.h:190:17:190:23 | replace | 0 | const_iterator | -| stl.h:190:17:190:23 | replace | 1 | func:0 | -| stl.h:190:17:190:23 | replace | 2 | func:0 | +| stl.h:189:42:189:47 | insert | 1 | func:0 | +| stl.h:189:42:189:47 | insert | 2 | func:0 | +| stl.h:190:17:190:23 | replace | 0 | size_type | +| stl.h:190:17:190:23 | replace | 1 | size_type | +| stl.h:190:17:190:23 | replace | 2 | const basic_string & | | stl.h:191:17:191:23 | replace | 0 | size_type | | stl.h:191:17:191:23 | replace | 1 | size_type | -| stl.h:191:17:191:23 | replace | 2 | const basic_string & | -| stl.h:192:13:192:16 | copy | 0 | size_type | +| stl.h:191:17:191:23 | replace | 2 | size_type | +| stl.h:191:17:191:23 | replace | 3 | class:0 | +| stl.h:192:13:192:16 | copy | 0 | class:0 * | | stl.h:192:13:192:16 | copy | 1 | size_type | | stl.h:192:13:192:16 | copy | 2 | size_type | -| stl.h:192:13:192:16 | copy | 3 | class:0 | -| stl.h:193:8:193:12 | clear | 0 | class:0 * | -| stl.h:193:8:193:12 | clear | 1 | size_type | -| stl.h:193:8:193:12 | clear | 2 | size_type | -| stl.h:195:8:195:11 | swap | 0 | size_type | -| stl.h:195:8:195:11 | swap | 1 | size_type | +| stl.h:194:16:194:21 | substr | 0 | size_type | +| stl.h:194:16:194:21 | substr | 1 | size_type | +| stl.h:195:8:195:11 | swap | 0 | basic_string & | | stl.h:198:94:198:102 | operator+ | 0 | const basic_string & | | stl.h:198:94:198:102 | operator+ | 1 | const basic_string & | | stl.h:199:94:199:102 | operator+ | 0 | const basic_string & |