Python: support callbacks to library calls

TODO:
The member predicate `LibraryLambdaMethod::getACall` is
currently too permissive.
Ideally, we would have `libraryCallHasLambdaArg`
as in Ruby. But even a more precise
`libraryCall` predicate might be fine.
This commit is contained in:
Rasmus Lerchedahl Petersen
2023-12-05 22:50:01 +01:00
parent 7565873e83
commit 17a0029585
3 changed files with 36 additions and 1 deletions

View File

@@ -91,6 +91,29 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
private module LibraryCallbackSummaries {
private class LibraryLambdaMethod extends SummarizedCallable {
LibraryLambdaMethod() { this = "<library method accepting a callback>" }
final override CallCfgNode getACall() {
exists(ExtractedDataFlowCall call | result.getNode() = call.getNode() |
not exists(call.getCallable())
)
}
final override ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(int i |
i in [0 .. 10] and
input = "Argument[" + i + "]" and
output = "Argument[" + i + "].Parameter[lambda-self]"
) and
preservesValue = true
}
}
}
private class SummarizedCallableFromModel extends SummarizedCallable {
string type;
string path;

View File

@@ -166,6 +166,9 @@ string getMadRepresentationSpecific(SummaryComponent sc) {
string getParameterPosition(ParameterPosition pos) {
pos.isSelf() and result = "self"
or
pos.isLambdaSelf() and
result = "lambda-self"
or
exists(int i |
pos.isPositional(i) and
result = i.toString()
@@ -181,6 +184,9 @@ string getParameterPosition(ParameterPosition pos) {
string getArgumentPosition(ArgumentPosition pos) {
pos.isSelf() and result = "self"
or
pos.isLambdaSelf() and
result = "lambda-self"
or
exists(int i |
pos.isPositional(i) and
result = i.toString()
@@ -305,6 +311,9 @@ ArgumentPosition parseParamBody(string s) {
or
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
}
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
@@ -321,4 +330,7 @@ ParameterPosition parseArgBody(string s) {
or
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
}

View File

@@ -45,4 +45,4 @@ def test_library_call():
for x in map(set, [1]):
pass
SINK(captured["x"]) #$ MISSING:captured
SINK(captured["x"]) #$ captured