C++: Don't wrap calls through function pointers in FunctionWithWrappers#20066
Merged
MathiasVP merged 3 commits intogithub:mainfrom Jul 16, 2025
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull Request Overview
This PR modifies the FunctionWithWrappers library to exclude calls through function pointers from being considered as wrapper functions. The change aims to simplify the library's behavior while unblocking upcoming improvements to call target resolution logic.
- Restricts wrapper function detection to direct function calls only (excluding function pointer calls)
- Updates change notes to document the impact on affected security queries
- Maintains the library's core functionality while reducing complexity
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| cpp/ql/lib/semmle/code/cpp/security/FunctionWithWrappers.qll | Changes Call to FunctionCall in two predicates to exclude function pointer calls |
| cpp/ql/lib/change-notes/2025-07-16-FunctionWithWrappers.md | Documents the library change for developers |
| cpp/ql/src/change-notes/2025-07-16-FunctionWithWrappers.md | Documents potential alert location changes in affected queries |
jketema
reviewed
Jul 16, 2025
Contributor
jketema
left a comment
There was a problem hiding this comment.
Looks sensible. One question.
| exists(Call call, Expr arg, Parameter sourceParam | | ||
| exists(FunctionCall call, Expr arg, Parameter sourceParam | | ||
| // there is a 'call' to 'target' with argument 'arg' at index 'targetParamIndex' | ||
| target = resolveCall(call) and |
Contributor
There was a problem hiding this comment.
Do we still need resolveCall here, or can we just do getTarget now?
Contributor
Author
There was a problem hiding this comment.
We can probably do getTarget, yeah. Will try it out!
| */ | ||
| predicate outermostWrapperFunctionCall(Expr arg, string callChain) { | ||
| exists(Function targetFunc, Call call, int argIndex | | ||
| exists(Function targetFunc, FunctionCall call, int argIndex | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I'll soon be making some improvements to the C++ call target resolution logic. However, one of the things making that change difficult is the old
FunctionWithWrapperslibrary.What is the
FunctionWithWrapperslibrary?The goal of the library is to put an alert location at the outermost wrapper of a low-level function call. The idea being that this outermost function is probably the function that the developers are more familiar with. So instead of making the low-level call your sink in a dataflow configuration you make the outermost wrapper (identified via the
FunctionWithWrapperslibrary) your sink. The library will then construct a string along the lines of "function f which calls function g which calls your sink".Why I don't like it
Honestly, I'm not really a fan of this library for a few reasons:
When using the
FunctionWithWrapperslibrary we'll get two alerts: one onwrap_sink1and one onwrap_sink2. If we simply marksinkas the sink we'll get 1 alert with 2 paths. This allows developers to fine-tune the number of paths via--max-paths.This PR
So ideally I'd like to simply remove its usage from the four queries that depend on it, and deprecate this library altogether. However, that would move a bunch of primary alert locations from a wrapper function to the "real" sink in the following queries:
cpp/path-injection(in the security-extended suite)cpp/sql-injection(in the security-extended suite)cpp/tainted-format-string(in the code scanning suite)cpp/command-line-injection(in the code scanning suite)So in order to unblock my upcoming work on improvements to call target resolution logic here's a simpler alternative: we simply stop considering calls to function pointers as potential function wrappers. I actually think that's a reasonable change in itself.
The DCA looks scary because of all the alert diffs. But this really is just alert locations being moved in three queries because these alerts were previously on a wrapper function which called the "real" sink through a sequence of wrappers (where one of those calls was through a function pointer). See point 2 in the "why I don't like it" section for why this happens.
Also note that only 2 out of 330 results are in non-Samate projects.