Skip to content

Conversation

@MathiasVP
Copy link
Contributor

On main it's currently not possible to write a MaD summary for the following function:

template<int N, typename T>
void f(const T*, T*) { ... }

because the first template parameter fails the QL type-check here and thus we fail to compute the expected signature that can be specified in the MaD row's "signature" column.

(The example may look slightly contrived, but it's important for writing summaries for certain STL functions that abuse template parameters to pick various overloads based on constant computations that evaluate to constant Booleans.)

Commit-by-commit review recommended.

Copilot AI review requested due to automatic review settings November 24, 2025 12:14
@MathiasVP MathiasVP requested a review from a team as a code owner November 24, 2025 12:14
@github-actions github-actions bot added the C++ label Nov 24, 2025
@MathiasVP MathiasVP added the no-change-note-required This PR does not need a change note label Nov 24, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enables MaD (Model-as-Data) summaries for C++ functions with non-type template parameters. Previously, functions like template<int N, typename T> void f(const T*, T*) could not have MaD summaries because the non-type parameter N would fail type-checking during signature computation. The fix filters out non-type template parameters when computing signatures, retaining only type template parameters.

Key changes:

  • Introduced predicates to filter and count only supported (type) template parameters
  • Updated signature computation to use filtered template parameter counts
  • Added documentation clarifying that non-type template parameters cannot be specified in MaD models

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll Added filtering predicates for type-only template parameters; updated signature computation to exclude non-type parameters; clarified documentation about non-type parameter limitations
cpp/ql/test/library-tests/dataflow/external-models/test.cpp Added test case with function using non-type template parameter (callWithNonTypeTemplate<10, int>)
cpp/ql/test/library-tests/dataflow/external-models/flow.ext.yml Added MaD model for callWithNonTypeTemplate<T> to test non-type parameter handling
cpp/ql/test/library-tests/dataflow/external-models/sources.expected Updated expected sources with new test case results
cpp/ql/test/library-tests/dataflow/external-models/sinks.expected Updated expected sinks with new test case results
cpp/ql/test/library-tests/dataflow/external-models/flow.expected Updated expected flow analysis results including new edges and nodes for non-type template test

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@MathiasVP
Copy link
Contributor Author

This PR enables MaD (Model-as-Data) summaries for C++ functions with non-type template parameters. Previously, functions like template<int N, typename T> void f(const T*, T*) could not have MaD summaries because the non-type parameter N would fail type-checking during signature computation. The fix filters out non-type template parameters when computing signatures, retaining only type template parameters.

Thanks for writing the exact same description as I wrote in the PR, Copilot. I'm sure this will be a great help to reviewers!

@jketema
Copy link
Contributor

jketema commented Nov 25, 2025

I'm not sure I like the approach taken here. In the sense that I'm not sure what callWithNonTypeTemplate<T> means in the MaD summary. Consider for example:

template<int N, typename T>
T callWithNonTypeTemplate(const T&);

template<typename T>
T callWithNonTypeTemplate(const T&);

void test_callWithNonTypeTemplate() {
	int x = ymlSource();
	int y = callWithNonTypeTemplate<10, int>(x);
	int z = callWithNonTypeTemplate<int>(x);
}

The two versions of callWithNonTypeTemplate could potentially have different behavior wrt. dataflow/taint tracking. How do I differentiate them in the MaD summary?

@MathiasVP
Copy link
Contributor Author

MathiasVP commented Nov 25, 2025

The two versions of callWithNonTypeTemplate could potentially have different behavior wrt. dataflow/taint tracking. How do I differentiate them in the MaD summary?

You cannot currently do that. We could make that possible, but as far as I know we have not had a reason yet to do this. I think this current approach has at least two benefits:

  1. It's fairly simple. I don't want to encode too much complex C++ into the syntax unless we have a good use-case for it, and the only use-care I am aware of right now is adding summaries for stuff like this from GCC's stl_pair.h:
    template<typename _U1, typename _U2, typename
	     enable_if<_PCCFP<_U1, _U2>::template
			 _MoveConstructiblePair<_U1, _U2>()
			&& !_PCCFP<_U1, _U2>::template
			 _ImplicitlyMoveConvertiblePair<_U1, _U2>(),
                       bool>::type=false>
explicit constexpr pair(pair<_U1, _U2>&& __p)
: first(std::forward<_U1>(__p.first)),
	second(std::forward<_U2>(__p.second)) { }

where we currently cannot add a model for this constructor because of the std::enable_if.
2. In the summary generation library there's an assumption that, if we can generate a summary for a method/member function in a base class then an override will have the same dataflow behavior. That's obviously not guaranteed to hold, but it (probably) matches the way people programs.
Similarly, I think people overload functions similar to callWithNonTypeTemplate above to get optimized implementations which will have the same dataflow behavior, and so hopefully it makes sense for the same summary to be applied to all overloads that matches the signature.

@MathiasVP
Copy link
Contributor Author

I discussed this with Jeroen just now, and we agreed to restrict this PR to only ignore non-type template parameters at the end of the template parameter list. That makes it easier to eventually add support for specifying non-type template parameters in MaD syntax in the future, and the only thing we need for the upcoming STL models are hopefully non-type template parameters in tail positions.

@MathiasVP
Copy link
Contributor Author

I discussed this with Jeroen just now, and we agreed to restrict this PR to only ignore non-type template parameters at the end of the template parameter list.

Should be done now in 05737af

Copy link
Contributor

@jketema jketema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@MathiasVP MathiasVP merged commit d869b00 into github:main Nov 26, 2025
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C++ no-change-note-required This PR does not need a change note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants