diff --git a/cpp/ql/lib/change-notes/2023-10-12-additional-call-targets.md b/cpp/ql/lib/change-notes/2023-10-12-additional-call-targets.md new file mode 100644 index 00000000000..f87fba1f172 --- /dev/null +++ b/cpp/ql/lib/change-notes/2023-10-12-additional-call-targets.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* Added a new class `AdditionalCallTarget` for specifying additional call targets. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll index 9774ad7168b..86c64edc847 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowDispatch.qll @@ -7,9 +7,12 @@ private import DataFlowImplCommon as DataFlowImplCommon /** * Gets a function that might be called by `call`. + * + * This predicate does not take additional call targets + * from `AdditionalCallTarget` into account. */ cached -DataFlowCallable viableCallable(DataFlowCall call) { +DataFlowCallable defaultViableCallable(DataFlowCall call) { DataFlowImplCommon::forceCachingInSameStage() and result = call.getStaticCallTarget() or @@ -29,6 +32,17 @@ DataFlowCallable viableCallable(DataFlowCall call) { result = call.(VirtualDispatch::DataSensitiveCall).resolve() } +/** + * Gets a function that might be called by `call`. + */ +cached +DataFlowCallable viableCallable(DataFlowCall call) { + result = defaultViableCallable(call) + or + // Additional call targets + result = any(AdditionalCallTarget additional).viableTarget(call.getUnconvertedResultExpression()) +} + /** * Provides virtual dispatch support compatible with the original * implementation of `semmle.code.cpp.security.TaintTracking`. diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index fd628df907e..992e995094e 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -14,6 +14,7 @@ private import DataFlowPrivate private import ModelUtil private import SsaInternals as Ssa private import DataFlowImplCommon as DataFlowImplCommon +private import codeql.util.Unit /** * The IR dataflow graph consists of the following nodes: @@ -2237,3 +2238,43 @@ module InstructionBarrierGuard(x)` as if the user had written `f(x)`. + exists(FunctionTemplateInstantiation inst | + inst.getTemplate().hasName("call_template_argument") and + call.getTarget() = inst and + result = inst.getTemplateArgument(0).(FunctionAccess).getTarget() + ) + } +} + module IRConfig implements ConfigSig { predicate isSource(Node src) { src.asExpr() instanceof NewExpr diff --git a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected index 9c30be7684a..f6284e9713a 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected +++ b/cpp/ql/test/library-tests/dataflow/fields/ir-path-flow.expected @@ -770,6 +770,9 @@ edges | simple.cpp:92:7:92:7 | a indirection [post update] [i] | simple.cpp:94:10:94:11 | a2 indirection [i] | | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... | | simple.cpp:94:10:94:11 | a2 indirection [i] | simple.cpp:94:13:94:13 | i | +| simple.cpp:103:24:103:24 | x | simple.cpp:104:14:104:14 | x | +| simple.cpp:108:17:108:26 | call to user_input | simple.cpp:109:43:109:43 | x | +| simple.cpp:109:43:109:43 | x | simple.cpp:103:24:103:24 | x | | struct_init.c:14:24:14:25 | ab indirection [a] | struct_init.c:15:8:15:9 | ab indirection [a] | | struct_init.c:15:8:15:9 | ab indirection [a] | struct_init.c:15:12:15:12 | a | | struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:22:8:22:9 | ab indirection [a] | @@ -1576,6 +1579,10 @@ nodes | simple.cpp:92:11:92:20 | call to user_input | semmle.label | call to user_input | | simple.cpp:94:10:94:11 | a2 indirection [i] | semmle.label | a2 indirection [i] | | simple.cpp:94:13:94:13 | i | semmle.label | i | +| simple.cpp:103:24:103:24 | x | semmle.label | x | +| simple.cpp:104:14:104:14 | x | semmle.label | x | +| simple.cpp:108:17:108:26 | call to user_input | semmle.label | call to user_input | +| simple.cpp:109:43:109:43 | x | semmle.label | x | | struct_init.c:14:24:14:25 | ab indirection [a] | semmle.label | ab indirection [a] | | struct_init.c:15:8:15:9 | ab indirection [a] | semmle.label | ab indirection [a] | | struct_init.c:15:12:15:12 | a | semmle.label | a | @@ -1782,6 +1789,7 @@ subpaths | simple.cpp:67:13:67:13 | i | simple.cpp:65:11:65:20 | call to user_input | simple.cpp:67:13:67:13 | i | i flows from $@ | simple.cpp:65:11:65:20 | call to user_input | call to user_input | | simple.cpp:84:14:84:20 | call to getf2f1 | simple.cpp:83:17:83:26 | call to user_input | simple.cpp:84:14:84:20 | call to getf2f1 | call to getf2f1 flows from $@ | simple.cpp:83:17:83:26 | call to user_input | call to user_input | | simple.cpp:94:13:94:13 | i | simple.cpp:92:11:92:20 | call to user_input | simple.cpp:94:13:94:13 | i | i flows from $@ | simple.cpp:92:11:92:20 | call to user_input | call to user_input | +| simple.cpp:104:14:104:14 | x | simple.cpp:108:17:108:26 | call to user_input | simple.cpp:104:14:104:14 | x | x flows from $@ | simple.cpp:108:17:108:26 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:20:20:20:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:20:20:20:29 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:27:7:27:16 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:27:7:27:16 | call to user_input | call to user_input | | struct_init.c:15:12:15:12 | a | struct_init.c:40:20:40:29 | call to user_input | struct_init.c:15:12:15:12 | a | a flows from $@ | struct_init.c:40:20:40:29 | call to user_input | call to user_input | diff --git a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp index e4d4f70edb0..36756689855 100644 --- a/cpp/ql/test/library-tests/dataflow/fields/simple.cpp +++ b/cpp/ql/test/library-tests/dataflow/fields/simple.cpp @@ -94,4 +94,21 @@ void single_field_test_typedef(A_typedef a) sink(a2.i); //$ ast,ir } +namespace TestAdditionalCallTargets { + + using TakesIntReturnsVoid = void(*)(int); + template + void call_template_argument(int); + + void call_sink(int x) { + sink(x); // $ ir + } + + void test_additional_call_targets() { + int x = user_input(); + call_template_argument(x); + } + +} + } // namespace Simple