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/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 & |