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

Data flow: Implement new lambda flow interface for Java #17979

Draft
wants to merge 1 commit into
base: dataflow/lambda-flow
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ private import semmle.code.java.dataflow.TypeFlow
private import semmle.code.java.dataflow.FlowSteps
private import DataFlowPrivate
private import DataFlowUtil
private import DataFlowDispatch
private import FlowSummaryImpl as FlowSummaryImpl
private import DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.java.controlflow.Guards
Expand Down Expand Up @@ -68,7 +69,9 @@ private module Cached {
TMapKeyContent() or
TMapValueContent() or
TCapturedVariableContent(CapturedVariable v) or
TSyntheticFieldContent(SyntheticField s)
TSyntheticFieldContent(SyntheticField s) or
TLambdaReturn(Method m) or
TLambdaArgument(Method m, ArgumentPosition pos)

cached
newtype TContentApprox =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ private newtype TDataFlowCall =
TCall(Call c) or
TSummaryCall(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
} or
TLambdaSynthCall(Node node) { lambdaCreationHelper(node, _, _) }

/** A call relevant for data flow. Includes both source calls and synthesized calls. */
class DataFlowCall extends TDataFlowCall {
Expand Down Expand Up @@ -526,6 +527,19 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
override Location getLocation() { result = c.getLocation() }
}

/** A synthesized call inside a `SummarizedCallable`. */
class LambdaSynthCall extends DataFlowCall, TLambdaSynthCall {
private Node node;

LambdaSynthCall() { this = TLambdaSynthCall(node) }

override DataFlowCallable getEnclosingCallable() { result.asCallable() = node.getEnclosingCallable() }

override string toString() { result = "[synthetic] call to " + node }

override Location getLocation() { result = node.getLocation() }
}

class NodeRegion instanceof BasicBlock {
string toString() { result = "NodeRegion" }

Expand Down Expand Up @@ -585,8 +599,7 @@ predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode }

class LambdaCallKind = Method; // the "apply" method in the functional interface

/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
predicate lambdaCreationHelper(Node creation, LambdaCallKind kind, DataFlowCallable c) {
exists(ClassInstanceExpr func, Interface t, FunctionalInterface interface |
creation.asExpr() = func and
func.getAnonymousClass().getAMethod() = c.asCallable() and
Expand All @@ -597,6 +610,12 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
)
}

/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c, DataFlowCall synthCall) {
synthCall = TLambdaSynthCall(creation) and
lambdaCreationHelper(creation, kind, c)
}

/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
receiver.(FlowSummaryNode).getSummaryNode() = call.(SummaryCall).getReceiver() and
Expand Down Expand Up @@ -766,3 +785,15 @@ predicate containerContent(ContentSet c) {
c instanceof MapKeyContent or
c instanceof MapValueContent
}

Content getLambdaReturnContent(LambdaCallKind kind) {
result = TLambdaReturn(kind)
}

Content getLambdaArgumentContent(LambdaCallKind kind, ArgumentPosition pos) {
result = TLambdaArgument(kind, pos)
}

predicate isLambdaInstanceParameter(ParameterNode p) {
exists(DataFlowCallable c | lambdaCreationHelper(_, _, c) and p.isParameterOf(c, -1))
}
26 changes: 26 additions & 0 deletions java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

private import java
private import DataFlowPrivate
private import DataFlowDispatch
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dataflow.ExternalFlow
Expand Down Expand Up @@ -359,6 +360,31 @@ class SyntheticFieldContent extends Content, TSyntheticFieldContent {
override string toString() { result = s.toString() }
}

class LambdaReturnContent extends Content, TLambdaReturn {
Method m;

LambdaReturnContent() { this = TLambdaReturn(m) }

override DataFlowType getType() {
result = getErasedRepr(m.getReturnType())
}

override string toString() { result = "<lambda-return>" }
}

class LambdaArgumentContent extends Content, TLambdaArgument {
Method m;
ArgumentPosition pos;

LambdaArgumentContent() {
this = TLambdaArgument(m, pos)
}

override DataFlowType getType() {
result = getErasedRepr(m.getParameter(pos).getType())
}
override string toString() { result = "<lambda-argument>" + pos.toString() }
}
/**
* An entity that represents a set of `Content`s.
*
Expand Down
Loading