Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: Move min/maxParameter methods to Function class #18871

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Python: Move min/maxParameter methods to Function
These seem generally useful outside of points-to, and so it might be
better to add them to the `Function` class instead.

I took the liberty of renaming these to say `Arguments` rather than
`Parameters`, as this is more in line with the nomenclature that we're
using elsewhere. (The internal points-to methods retain the old names.)

I'm somewhat ambivalent about the behaviour of `getMaxParameters` on
functions with `*varargs`. The hard-coded `INT_MAX` return value is
somewhat awkward, but the alternative (to only have the predicate
defined when a specific maximum exists) seems like it would potentially
cause a lot of headaches.
  • Loading branch information
tausbn committed Feb 26, 2025
commit 3956a1fea8d1c08ab7822487f5aa0cbf33867b60
12 changes: 12 additions & 0 deletions python/ql/lib/semmle/python/Function.qll
Original file line number Diff line number Diff line change
@@ -163,6 +163,18 @@ class Function extends Function_, Scope, AstNode {
ret.getValue() = result.getNode()
)
}

/** Gets the minimum number of positional arguments that can be correctly passed to this function. */
int getMinArguments() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Naming: Should these be getMinPositionalArguments, something like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a mouthful (and it suggests the existence of getMinKeywordArguments, which I'm not entirely sure makes sense), but it's probably a good idea to proactively disambiguate things here. At the very least, renaming it to something shorter will be easy to do if we feel like it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 11e6194.

result = count(this.getAnArg()) - count(this.getDefinition().getArgs().getADefault())
}

/** Gets the maximum number of positional arguments that can be correctly passed to this function. */
int getMaxArguments() {
if exists(this.getVararg())
then result = 2147483647 // INT_MAX
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ooh this is an interesting trap. I suggest at least putting it in the QLDoc, i.e. if the function doesn't take varargs, the result is INT_MAX.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think you've got a superfluous negation there (if the function does take varargs, the result is INT_MAX), but I agree this should be documented better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 11e6194.

else result = count(this.getAnArg())
}
}

/** A def statement. Note that FunctionDef extends Assign as a function definition binds the newly created function */
16 changes: 2 additions & 14 deletions python/ql/lib/semmle/python/objects/ObjectAPI.qll
Original file line number Diff line number Diff line change
@@ -738,21 +738,9 @@ class PythonFunctionValue extends FunctionValue {
else result = "function " + this.getQualifiedName()
}

override int minParameters() {
exists(Function f |
f = this.getScope() and
result = count(f.getAnArg()) - count(f.getDefinition().getArgs().getADefault())
)
}
override int minParameters() { result = this.getScope().getMinArguments() }

override int maxParameters() {
exists(Function f |
f = this.getScope() and
if exists(f.getVararg())
then result = 2147483647 // INT_MAX
else result = count(f.getAnArg())
)
}
override int maxParameters() { result = this.getScope().getMaxArguments() }

/** Gets a control flow node corresponding to a return statement in this function */
ControlFlowNode getAReturnedNode() { result = this.getScope().getAReturnValueFlowNode() }