mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #17483 from smowton/smowton/feature/csharp-dataflow-fewer-nodes-including-virtual-dispatch
C#: Restrict dataflow node creation to source and source-referenced entities [virtual-dispatch-inclusive variant]
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `DataFlow::Node` instances are no longer created for library methods and fields that are not callable (either statically or dynamically) or otherwise referred to from source code. This may affect third-party queries that use these nodes to identify library methods or fields that are present in DLL files where those methods or fields are unreferenced. If this presents a problem, consider using `Callable` and other non-dataflow classes to identify such library entities.
|
||||
@@ -995,6 +995,52 @@ private class InstanceCallable extends Callable {
|
||||
Location getARelevantLocation() { result = l }
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable which is either itself defined in source or which is the target
|
||||
* of some call in source, and therefore ought to have dataflow nodes created.
|
||||
*
|
||||
* Note that for library methods these are always unbound declarations, since
|
||||
* generic instantiations never have dataflow nodes constructed.
|
||||
*/
|
||||
private class CallableUsedInSource extends Callable {
|
||||
CallableUsedInSource() {
|
||||
// Should generate nodes even for abstract methods declared in source
|
||||
this.fromSource()
|
||||
or
|
||||
// Should generate nodes even for synthetic methods derived from source
|
||||
this.hasBody()
|
||||
or
|
||||
exists(Callable target |
|
||||
exists(Call c |
|
||||
// Note that getADynamicTarget does not always include getTarget.
|
||||
target = c.getTarget()
|
||||
or
|
||||
// Note that getARuntimeTarget cannot be used here, because the
|
||||
// DelegateLikeCall case depends on lambda-flow, which in turn
|
||||
// uses the dataflow library; hence this would introduce recursion
|
||||
// into the definition of data-flow nodes.
|
||||
exists(DispatchCall dc | c = dc.getCall() | target = dc.getADynamicTarget())
|
||||
)
|
||||
or
|
||||
target = any(CallableAccess ca).getTarget()
|
||||
|
|
||||
this = target.getUnboundDeclaration()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A field or property which is either itself defined in source or which is the target
|
||||
* of some access in source, and therefore ought to have dataflow nodes created.
|
||||
*/
|
||||
private class FieldOrPropertyUsedInSource extends FieldOrProperty {
|
||||
FieldOrPropertyUsedInSource() {
|
||||
this.fromSource()
|
||||
or
|
||||
this.getAnAccess().fromSource()
|
||||
}
|
||||
}
|
||||
|
||||
/** A collection of cached types and predicates to be evaluated in the same stage. */
|
||||
cached
|
||||
private module Cached {
|
||||
@@ -1018,8 +1064,13 @@ private module Cached {
|
||||
TAssignableDefinitionNode(AssignableDefinition def, ControlFlow::Node cfn) {
|
||||
cfn = def.getExpr().getAControlFlowNode()
|
||||
} or
|
||||
TExplicitParameterNode(Parameter p, DataFlowCallable c) { p = c.asCallable(_).getAParameter() } or
|
||||
TInstanceParameterNode(InstanceCallable c, Location l) { l = c.getARelevantLocation() } or
|
||||
TExplicitParameterNode(Parameter p, DataFlowCallable c) {
|
||||
p = c.asCallable(_).(CallableUsedInSource).getAParameter()
|
||||
} or
|
||||
TInstanceParameterNode(InstanceCallable c, Location l) {
|
||||
c instanceof CallableUsedInSource and
|
||||
l = c.getARelevantLocation()
|
||||
} or
|
||||
TDelegateSelfReferenceNode(Callable c) { lambdaCreationExpr(_, c) } or
|
||||
TLocalFunctionCreationNode(ControlFlow::Nodes::ElementNode cfn, Boolean isPostUpdate) {
|
||||
cfn.getAstNode() instanceof LocalFunctionStmt
|
||||
@@ -1055,11 +1106,13 @@ private module Cached {
|
||||
or
|
||||
lambdaCallExpr(_, cfn)
|
||||
} or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
|
||||
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) {
|
||||
sn.getSummarizedCallable() instanceof CallableUsedInSource
|
||||
} or
|
||||
TParamsArgumentNode(ControlFlow::Node callCfn) {
|
||||
callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode()
|
||||
} or
|
||||
TFlowInsensitiveFieldNode(FieldOrProperty f) { f.isFieldLike() } or
|
||||
TFlowInsensitiveFieldNode(FieldOrPropertyUsedInSource f) { f.isFieldLike() } or
|
||||
TFlowInsensitiveCapturedVariableNode(LocalScopeVariable v) { v.isCaptured() } or
|
||||
TInstanceParameterAccessNode(ControlFlow::Node cfn, Boolean isPostUpdate) {
|
||||
cfn = getAPrimaryConstructorParameterCfn(_)
|
||||
|
||||
Reference in New Issue
Block a user