- Notifications
You must be signed in to change notification settings - Fork1.7k
C++: Don't wrap calls through function pointers inFunctionWithWrappers
#20066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
C++: Don't wrap calls through function pointers inFunctionWithWrappers
#20066
Conversation
There was a problem hiding this 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 modifies theFunctionWithWrappers
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 | ChangesCall toFunctionCall 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Looks sensible. One question.
@@ -37,7 +37,7 @@ private predicate wrapperFunctionStep( | |||
not target.isVirtual() and | |||
not source.isVirtual() and | |||
source.hasDefinition() and | |||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Do we still needresolveCall
here, or can we just dogetTarget
now?
MathiasVPJul 16, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We can probably dogetTarget
, yeah. Will try it out!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Fixed in8b953e4
@@ -154,7 +154,7 @@ abstract class FunctionWithWrappers extends Function { | |||
* Whether 'arg' is an argument in a call to an outermost wrapper function of 'this' function. | |||
*/ | |||
predicate outermostWrapperFunctionCall(Expr arg, string callChain) { | |||
exists(Function targetFunc,Call call, int argIndex | | |||
exists(Function targetFunc,FunctionCall call, int argIndex | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Same as above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Fixed in8b953e4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
LGTM
a9fb49a
intogithub:mainUh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
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
FunctionWithWrappers
library.What is the
FunctionWithWrappers
library?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
FunctionWithWrappers
library) 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
FunctionWithWrappers
library we'll get two alerts: one onwrap_sink1
and one onwrap_sink2
. If we simply marksink
as 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.