Files
codeql/java/ql/lib/semmle/code/java/dispatch/WrappedInvocation.qll
Tom Hvitved 7024b07dd2 Java: Adapt to changes in FlowSummaryImpl
Missing manual models were added using the following code added to `FlowSummaryImpl.qll`:

```ql
    private predicate testsummaryElement(
      Input::SummarizedCallableBase c, string namespace, string type, boolean subtypes, string name,
      string signature, string ext, string originalInput, string originalOutput, string kind,
      string provenance, string model, boolean isExact
    ) {
      exists(string input, string output, Callable baseCallable |
        summaryModel(namespace, type, subtypes, name, signature, ext, originalInput, originalOutput,
          kind, provenance, model) and
        baseCallable = interpretElement(namespace, type, subtypes, name, signature, ext, isExact) and
        (
          c.asCallable() = baseCallable and input = originalInput and output = originalOutput
          or
          correspondingKotlinParameterDefaultsArgSpec(baseCallable, c.asCallable(), originalInput,
            input) and
          correspondingKotlinParameterDefaultsArgSpec(baseCallable, c.asCallable(), originalOutput,
            output)
        )
      )
    }

    private predicate testsummaryElement2(
      string namespace, string type, boolean subtypes, string name, string signature, string ext,
      string originalInput, string originalOutput, string kind, string provenance, string model,
      string namespace2, string type2
    ) {
      exists(Input::SummarizedCallableBase c |
        testsummaryElement(c, namespace2, type2, _, _, _, ext, originalInput, originalOutput, kind,
          provenance, model, false) and
        testsummaryElement(c, namespace, type, subtypes, name, _, _, _, _, _, provenance, _, true) and
        signature = paramsString(c.asCallable()) and
        not testsummaryElement(c, _, _, _, _, _, _, originalInput, originalOutput, kind, provenance,
          _, true)
      )
    }

    private string getAMissingManualModel(string namespace2, string type2) {
      exists(
        string namespace, string type, boolean subtypes, string name, string signature, string ext,
        string originalInput, string originalOutput, string kind, string provenance, string model
      |
        testsummaryElement2(namespace, type, subtypes, name, signature, ext, originalInput,
          originalOutput, kind, provenance, model, namespace2, type2) and
        result =
          "- [\"" + namespace + "\", \"" + type + "\", True, \"" + name + "\", \"" + signature +
            "\", \"\", \"" + originalInput + "\", \"" + originalOutput + "\", \"" + kind + "\", \"" +
            provenance + "\"]"
      )
    }
```
2026-01-26 12:40:15 +01:00

87 lines
2.7 KiB
Plaintext

/**
* Provides classes and predicates for reasoning about calls that may invoke one
* of their arguments.
*/
overlay[local?]
module;
import java
import VirtualDispatch
/**
* Holds if `m` might invoke `runmethod` through a functional interface on the
* `n`th parameter.
*/
private predicate runner(Method m, int n, Method runmethod) {
m.getParameterType(n).(RefType).getSourceDeclaration().(FunctionalInterface).getRunMethod() =
runmethod and
(
m.isNative()
or
exists(Parameter p, MethodCall ma, int j |
p = m.getParameter(n) and
ma.getEnclosingCallable() = m and
runner(pragma[only_bind_into](ma.getMethod().getSourceDeclaration()),
pragma[only_bind_into](j), _) and
ma.getArgument(pragma[only_bind_into](j)) = p.getAnAccess()
)
)
}
/**
* Gets an argument of `ma` on which `ma.getMethod()` might invoke `runmethod`
* through a functional interface. The argument is traced backwards through
* casts and variable assignments.
*/
private Expr getRunnerArgument(MethodCall ma, Method runmethod) {
exists(Method runner, int param |
runner(runner, param, runmethod) and
viableImpl_v2(ma) = runner and
result = ma.getArgument(param)
)
or
getRunnerArgument(ma, runmethod).(CastingExpr).getExpr() = result
or
pragma[only_bind_out](getRunnerArgument(ma, runmethod))
.(VarAccess)
.getVariable()
.getAnAssignedValue() = result
}
/**
* Gets a method that can be invoked through a functional interface as an
* argument to `ma`.
*/
Method getRunnerTarget(MethodCall ma) {
exists(Expr action, Method runmethod | action = getRunnerArgument(ma, runmethod) |
action.(FunctionalExpr).asMethod().getSourceDeclaration() = result
or
action.(ClassInstanceExpr).getAnonymousClass().getAMethod().getSourceDeclaration() = result and
result.overridesOrInstantiates*(runmethod)
)
}
import semmle.code.java.dataflow.FlowSummary
private predicate mayInvokeCallback(SrcMethod m, int n) {
m.getParameterType(n).(RefType).getSourceDeclaration() instanceof FunctionalInterface and
(not m.fromSource() or m.isNative() or m.getFile().getAbsolutePath().matches("%/test/stubs/%"))
}
private class SummarizedCallableWithCallback extends SummarizedCallable::Range {
private int pos;
SummarizedCallableWithCallback() { mayInvokeCallback(this.asCallable(), pos) }
override predicate propagatesFlow(
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
) {
input = "Argument[" + pos + "]" and
output = "Argument[" + pos + "].Parameter[-1]" and
preservesValue = true and
p = "hq-generated" and
isExact = true and
model = "heuristic-callback"
}
}