mirror of
https://github.com/github/codeql.git
synced 2026-04-23 15:55:18 +02:00
C#: Clean up implementation and remove CIL dataflow implementation.
This commit is contained in:
@@ -42,7 +42,9 @@ class Declaration extends DotNet::Declaration, Element, @cil_declaration {
|
||||
}
|
||||
}
|
||||
|
||||
private CS::Declaration toCSharpNonTypeParameter(Declaration d) { result.matchesHandle(d) }
|
||||
private CS::Declaration toCSharpNonTypeParameter(Declaration d) {
|
||||
result.(DotNet::Declaration).matchesHandle(d)
|
||||
}
|
||||
|
||||
private CS::TypeParameter toCSharpTypeParameter(TypeParameter tp) {
|
||||
toCSharpTypeParameterJoin(tp, result.getIndex(), result.getGeneric())
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
private import semmle.code.csharp.commons.QualifiedName
|
||||
import Element
|
||||
import Type
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A type container. Either a namespace (`Namespace`) or a type (`Type`).
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
import Member
|
||||
import Stmt
|
||||
import Type
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import TypeRef
|
||||
|
||||
@@ -558,8 +556,6 @@ class TrivialProperty extends Property {
|
||||
this.isAutoImplemented()
|
||||
or
|
||||
this.getGetter().trivialGetterField() = this.getSetter().trivialSetterField()
|
||||
or
|
||||
exists(CIL::TrivialProperty prop | this.matchesHandle(prop))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import Assignable
|
||||
import Callable
|
||||
import Element
|
||||
import Type
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import TypeRef
|
||||
|
||||
|
||||
@@ -3,56 +3,13 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
|
||||
private predicate isDisposeMethod(DotNet::Callable method) {
|
||||
private predicate isDisposeMethod(Callable method) {
|
||||
method.getName() = "Dispose" and
|
||||
method.getNumberOfParameters() = 0
|
||||
}
|
||||
|
||||
private predicate cilVariableReadFlowsToNode(CIL::Variable variable, DataFlow::Node n) {
|
||||
n.asExpr() = variable.getARead()
|
||||
or
|
||||
exists(DataFlow::Node mid |
|
||||
cilVariableReadFlowsToNode(variable, mid) and
|
||||
DataFlow::localFlowStep(mid, n)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate cilVariableReadFlowsTo(CIL::Variable variable, CIL::DataFlowNode n) {
|
||||
cilVariableReadFlowsToNode(variable, DataFlow::exprNode(n))
|
||||
}
|
||||
|
||||
private predicate disposedCilVariable(CIL::Variable variable) {
|
||||
// `variable` is the `this` parameter on a dispose method.
|
||||
isDisposeMethod(variable.(CIL::ThisParameter).getMethod())
|
||||
or
|
||||
// `variable` is passed to a method that disposes it.
|
||||
exists(CIL::Call call, CIL::Parameter param |
|
||||
cilVariableReadFlowsTo(variable, call.getArgumentForParameter(param)) and
|
||||
disposedCilVariable(param)
|
||||
)
|
||||
or
|
||||
// A parameter is disposed if its source declaration is disposed
|
||||
disposedCilVariable(variable.(CIL::Parameter).getUnboundDeclaration())
|
||||
or
|
||||
// A variable is disposed if it's assigned to another variable
|
||||
// that may be disposed.
|
||||
exists(CIL::WriteAccess write |
|
||||
cilVariableReadFlowsTo(variable, write.getExpr()) and
|
||||
disposedCilVariable(write.getTarget())
|
||||
)
|
||||
}
|
||||
|
||||
private predicate disposedCSharpVariable(Variable variable) {
|
||||
// A C# parameter is disposed if its corresponding CIL parameter is disposed
|
||||
exists(CIL::Method m, CIL::Parameter p, int i |
|
||||
disposedCilVariable(p) and p = m.getRawParameter(i)
|
||||
|
|
||||
variable = any(Callable c2 | c2.matchesHandle(m)).getRawParameter(i)
|
||||
)
|
||||
or
|
||||
// Call to a method that disposes it
|
||||
exists(Call call, int arg, VariableRead read |
|
||||
read.getTarget() = variable and
|
||||
@@ -83,7 +40,4 @@ private predicate disposedCSharpVariable(Variable variable) {
|
||||
* Hold if `variable` might be disposed.
|
||||
* This is a conservative overestimate.
|
||||
*/
|
||||
predicate mayBeDisposed(DotNet::Variable variable) {
|
||||
disposedCSharpVariable(variable) or
|
||||
disposedCilVariable(variable)
|
||||
}
|
||||
predicate mayBeDisposed(Variable variable) { disposedCSharpVariable(variable) }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/** Provides predicates for working with fully qualified names. */
|
||||
|
||||
private import csharp
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* Holds if namespace `n` has the qualified name `qualifier`.`name`.
|
||||
@@ -9,8 +8,8 @@ private import dotnet
|
||||
* For example if the qualified name is `System.Collections.Generic`, then
|
||||
* `qualifier`=`System.Collections` and `name`=`Generic`.
|
||||
*/
|
||||
predicate namespaceHasQualifiedName(DotNet::Namespace n, string qualifier, string name) {
|
||||
if n instanceof DotNet::GlobalNamespace
|
||||
predicate namespaceHasQualifiedName(Namespace n, string qualifier, string name) {
|
||||
if n instanceof GlobalNamespace
|
||||
then qualifier = "" and name = ""
|
||||
else (
|
||||
exists(string pqualifier, string pname |
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import ControlFlow::SuccessorTypes
|
||||
private import semmle.code.csharp.commons.Assertions
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
@@ -844,8 +843,6 @@ class NullGuardedDataFlowNode extends GuardedDataFlowNode {
|
||||
|
||||
/** INTERNAL: Do not use. */
|
||||
module Internal {
|
||||
private import semmle.code.cil.CallableReturns
|
||||
|
||||
newtype TAbstractValue =
|
||||
TBooleanValue(boolean b) { b = true or b = false } or
|
||||
TIntegerValue(int i) { i = any(Expr e).getValue().toInt() } or
|
||||
@@ -856,20 +853,11 @@ module Internal {
|
||||
} or
|
||||
TEmptyCollectionValue(boolean b) { b = true or b = false }
|
||||
|
||||
/** A callable that always returns a `null` value. */
|
||||
private class NullCallable extends Callable {
|
||||
NullCallable() {
|
||||
exists(CIL::Method m | m.matchesHandle(this) | alwaysNullMethod(m) and not m.isVirtual())
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if expression `e` is a `null` value. */
|
||||
predicate nullValue(Expr e) {
|
||||
e instanceof NullLiteral
|
||||
or
|
||||
e instanceof DefaultValueExpr and e.getType().isRefType()
|
||||
or
|
||||
e.(Call).getTarget().getUnboundDeclaration() instanceof NullCallable
|
||||
}
|
||||
|
||||
/** Holds if expression `e2` is a `null` value whenever `e1` is. */
|
||||
@@ -890,11 +878,7 @@ module Internal {
|
||||
|
||||
/** A callable that always returns a non-`null` value. */
|
||||
private class NonNullCallable extends Callable {
|
||||
NonNullCallable() {
|
||||
exists(CIL::Method m | m.matchesHandle(this) | alwaysNotNullMethod(m) and not m.isVirtual())
|
||||
or
|
||||
this = any(SystemObjectClass c).getGetTypeMethod()
|
||||
}
|
||||
NonNullCallable() { this = any(SystemObjectClass c).getGetTypeMethod() }
|
||||
}
|
||||
|
||||
/** Holds if expression `e` is a non-`null` value. */
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import cil
|
||||
private import semmle.code.cil.CallableReturns
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.commons.Assertions
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
@@ -39,15 +37,6 @@ private class ThrowingCall extends NonReturningCall {
|
||||
or
|
||||
this.(FailingAssertion).getAssertionFailure().isException(c.getExceptionClass())
|
||||
or
|
||||
exists(Callable target, CIL::Method m, CIL::Type ex |
|
||||
target = this.getTarget() and
|
||||
not target.hasBody() and
|
||||
target.matchesHandle(m) and
|
||||
alwaysThrowsException(m, ex) and
|
||||
c.getExceptionClass().matchesHandle(ex) and
|
||||
not m.isVirtual()
|
||||
)
|
||||
or
|
||||
this =
|
||||
any(MethodCall mc |
|
||||
mc.getTarget()
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import cil
|
||||
private import semmle.code.csharp.dataflow.Nullness
|
||||
private import semmle.code.cil.CallableReturns as CR
|
||||
|
||||
private predicate finalCallable(Callable c) {
|
||||
not c.(Virtualizable).isVirtual() and
|
||||
@@ -15,19 +13,11 @@ private predicate finalCallable(Callable c) {
|
||||
/** Holds if callable `c` always returns null. */
|
||||
predicate alwaysNullCallable(Callable c) {
|
||||
finalCallable(c) and
|
||||
(
|
||||
exists(CIL::Method m | m.matchesHandle(c) | CR::alwaysNullMethod(m))
|
||||
or
|
||||
forex(Expr e | c.canReturn(e) | e instanceof AlwaysNullExpr)
|
||||
)
|
||||
forex(Expr e | c.canReturn(e) | e instanceof AlwaysNullExpr)
|
||||
}
|
||||
|
||||
/** Holds if callable `c` always returns a non-null value. */
|
||||
predicate alwaysNotNullCallable(Callable c) {
|
||||
finalCallable(c) and
|
||||
(
|
||||
exists(CIL::Method m | m.matchesHandle(c) | CR::alwaysNotNullMethod(m))
|
||||
or
|
||||
forex(Expr e | c.canReturn(e) | e instanceof NonNullExpr)
|
||||
)
|
||||
forex(Expr e | c.canReturn(e) | e instanceof NonNullExpr)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
private import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import DataFlowImplCommon as DataFlowImplCommon
|
||||
private import DataFlowPublic
|
||||
private import DataFlowPrivate
|
||||
@@ -14,29 +12,12 @@ private import semmle.code.csharp.frameworks.system.collections.Generic
|
||||
/**
|
||||
* Gets a source declaration of callable `c` that has a body or has
|
||||
* a flow summary.
|
||||
*
|
||||
* If the callable has both CIL and source code, return only the source
|
||||
* code version.
|
||||
*/
|
||||
DotNet::Callable getCallableForDataFlow(DotNet::Callable c) {
|
||||
exists(DotNet::Callable unboundDecl | unboundDecl = c.getUnboundDeclaration() |
|
||||
result.hasBody() and
|
||||
if unboundDecl.getFile().fromSource()
|
||||
then
|
||||
// C# callable with C# implementation in the database
|
||||
result = unboundDecl
|
||||
else
|
||||
if unboundDecl instanceof CIL::Callable
|
||||
then
|
||||
// CIL callable with C# implementation in the database
|
||||
unboundDecl.matchesHandle(result.(Callable))
|
||||
or
|
||||
// CIL callable without C# implementation in the database
|
||||
not unboundDecl.matchesHandle(any(Callable k | k.hasBody())) and
|
||||
result = unboundDecl
|
||||
else
|
||||
// C# callable without C# implementation in the database
|
||||
unboundDecl.matchesHandle(result.(CIL::Callable))
|
||||
Callable getCallableForDataFlow(Callable c) {
|
||||
exists(Callable unboundDecl | unboundDecl = c.getUnboundDeclaration() |
|
||||
unboundDecl.hasBody() and
|
||||
unboundDecl.getFile().fromSource() and
|
||||
result = unboundDecl
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,7 +48,7 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
newtype TDataFlowCallable =
|
||||
TDotNetCallable(DotNet::Callable c) { c.isUnboundDeclaration() } or
|
||||
TCallable(Callable c) { c.isUnboundDeclaration() } or
|
||||
TSummarizedCallable(DataFlowSummarizedCallable sc) or
|
||||
TFieldOrPropertyCallable(FieldOrProperty f) or
|
||||
TCapturedVariableCallable(LocalScopeVariable v) { v.isCaptured() }
|
||||
@@ -81,10 +62,6 @@ private module Cached {
|
||||
TExplicitDelegateLikeCall(ControlFlow::Nodes::ElementNode cfn, DelegateLikeCall dc) {
|
||||
cfn.getAstNode() = dc
|
||||
} or
|
||||
TCilCall(CIL::Call call) {
|
||||
// No need to include calls that are compiled from source
|
||||
not call.getImplementation().getMethod().compiledFromSource()
|
||||
} or
|
||||
TSummaryCall(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
|
||||
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
|
||||
}
|
||||
@@ -197,7 +174,7 @@ class RefReturnKind extends OutRefReturnKind, TRefReturnKind {
|
||||
/** A callable used for data flow. */
|
||||
class DataFlowCallable extends TDataFlowCallable {
|
||||
/** Gets the underlying source code callable, if any. */
|
||||
DotNet::Callable asCallable() { this = TDotNetCallable(result) }
|
||||
Callable asCallable() { this = TCallable(result) }
|
||||
|
||||
/** Gets the underlying summarized callable, if any. */
|
||||
FlowSummary::SummarizedCallable asSummarizedCallable() { this = TSummarizedCallable(result) }
|
||||
@@ -208,7 +185,7 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
LocalScopeVariable asCapturedVariable() { this = TCapturedVariableCallable(result) }
|
||||
|
||||
/** Gets the underlying callable. */
|
||||
DotNet::Callable getUnderlyingCallable() {
|
||||
Callable getUnderlyingCallable() {
|
||||
result = this.asCallable() or result = this.asSummarizedCallable()
|
||||
}
|
||||
|
||||
@@ -235,8 +212,7 @@ class DataFlowCallable extends TDataFlowCallable {
|
||||
abstract class DataFlowCall extends TDataFlowCall {
|
||||
/**
|
||||
* Gets a run-time target of this call. A target is always a source
|
||||
* declaration, and if the callable has both CIL and source code, only
|
||||
* the source code version is returned.
|
||||
* declaration.
|
||||
*/
|
||||
abstract DataFlowCallable getARuntimeTarget();
|
||||
|
||||
@@ -250,7 +226,7 @@ abstract class DataFlowCall extends TDataFlowCall {
|
||||
abstract DataFlowCallable getEnclosingCallable();
|
||||
|
||||
/** Gets the underlying expression, if any. */
|
||||
final DotNet::Expr getExpr() { result = this.getNode().asExpr() }
|
||||
final Expr getExpr() { result = this.getNode().asExpr() }
|
||||
|
||||
/** Gets the argument at position `pos` of this call. */
|
||||
final ArgumentNode getArgument(ArgumentPosition pos) { result.argumentOf(this, pos) }
|
||||
@@ -348,33 +324,6 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
|
||||
override Location getLocation() { result = cfn.getLocation() }
|
||||
}
|
||||
|
||||
/** A CIL call relevant for data flow. */
|
||||
class CilDataFlowCall extends DataFlowCall, TCilCall {
|
||||
private CIL::Call call;
|
||||
|
||||
CilDataFlowCall() { this = TCilCall(call) }
|
||||
|
||||
/** Gets the underlying CIL call. */
|
||||
CIL::Call getCilCall() { result = call }
|
||||
|
||||
override DataFlowCallable getARuntimeTarget() {
|
||||
// There is no dispatch library for CIL, so do not consider overrides for now
|
||||
result.getUnderlyingCallable() = getCallableForDataFlow(call.getTarget())
|
||||
}
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
|
||||
|
||||
override DataFlow::ExprNode getNode() { result.getExpr() = call }
|
||||
|
||||
override DataFlowCallable getEnclosingCallable() {
|
||||
result.asCallable() = call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
override string toString() { result = call.toString() }
|
||||
|
||||
override Location getLocation() { result = call.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A synthesized call inside a callable with a flow summary.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
private import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import DataFlowPublic
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowImplCommon
|
||||
@@ -18,8 +16,6 @@ private import semmle.code.csharp.frameworks.NHibernate
|
||||
private import semmle.code.csharp.frameworks.Razor
|
||||
private import semmle.code.csharp.frameworks.system.Collections
|
||||
private import semmle.code.csharp.frameworks.system.threading.Tasks
|
||||
private import semmle.code.cil.Ssa::Ssa as CilSsa
|
||||
private import semmle.code.cil.internal.SsaImpl as CilSsaImpl
|
||||
private import codeql.util.Unit
|
||||
private import codeql.util.Boolean
|
||||
|
||||
@@ -57,15 +53,15 @@ abstract class NodeImpl extends Node {
|
||||
|
||||
/** Do not call: use `getType()` instead. */
|
||||
cached
|
||||
abstract DotNet::Type getTypeImpl();
|
||||
abstract Type getTypeImpl();
|
||||
|
||||
/** Gets the type of this node used for type pruning. */
|
||||
DataFlowType getDataFlowType() {
|
||||
forceCachingInSameStage() and
|
||||
exists(Type t0 | result.asGvnType() = Gvn::getGlobalValueNumber(t0) |
|
||||
t0 = getCSharpType(this.getType())
|
||||
t0 = this.getType()
|
||||
or
|
||||
not exists(getCSharpType(this.getType())) and
|
||||
not exists(this.getType()) and
|
||||
t0 instanceof ObjectType
|
||||
)
|
||||
}
|
||||
@@ -96,16 +92,12 @@ private DataFlowCallable getEnclosingStaticFieldOrProperty(Expr e) {
|
||||
|
||||
private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.asCallable() =
|
||||
[
|
||||
this.getExpr().(CIL::Expr).getEnclosingCallable().(DotNet::Callable),
|
||||
this.getControlFlowNodeImpl().getEnclosingCallable()
|
||||
]
|
||||
result.asCallable() = this.getControlFlowNodeImpl().getEnclosingCallable()
|
||||
or
|
||||
result = getEnclosingStaticFieldOrProperty(this.asExpr())
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() {
|
||||
override Type getTypeImpl() {
|
||||
forceCachingInSameStage() and
|
||||
result = this.getExpr().getType()
|
||||
}
|
||||
@@ -121,11 +113,6 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
|
||||
override string toStringImpl() {
|
||||
forceCachingInSameStage() and
|
||||
result = this.getControlFlowNodeImpl().toString()
|
||||
or
|
||||
exists(CIL::Expr e |
|
||||
this = TCilExprNode(e) and
|
||||
result = e.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,12 +247,6 @@ predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, No
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the CIL data-flow node for `node`, if any. */
|
||||
CIL::DataFlowNode asCilDataFlowNode(Node node) {
|
||||
result = node.asParameter() or
|
||||
result = node.asExpr()
|
||||
}
|
||||
|
||||
/** Provides logic related to captured variables. */
|
||||
module VariableCapture {
|
||||
private import codeql.dataflow.VariableCapture as Shared
|
||||
@@ -731,79 +712,6 @@ module LocalFlow {
|
||||
)
|
||||
}
|
||||
|
||||
private module CilFlow {
|
||||
/**
|
||||
* Holds if `nodeFrom` is a last node referencing SSA definition `def`, which
|
||||
* can reach `next`.
|
||||
*/
|
||||
private predicate localFlowCilSsaInput(
|
||||
Node nodeFrom, CilSsaImpl::DefinitionExt def, CilSsaImpl::DefinitionExt next
|
||||
) {
|
||||
exists(CIL::BasicBlock bb, int i | CilSsaImpl::lastRefBeforeRedefExt(def, bb, i, next) |
|
||||
def.definesAt(_, bb, i, _) and
|
||||
def = nodeFrom.(CilSsaDefinitionExtNode).getDefinition() and
|
||||
def != next
|
||||
or
|
||||
nodeFrom = TCilExprNode(bb.getNode(i).(CIL::ReadAccess))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
|
||||
* CIL SSA definition `def`.
|
||||
*/
|
||||
private predicate localCilSsaFlowStep(CilSsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
// Flow into SSA definition
|
||||
exists(CIL::VariableUpdate vu |
|
||||
vu = def.(CilSsa::Definition).getVariableUpdate() and
|
||||
vu.getSource() = asCilDataFlowNode(nodeFrom) and
|
||||
def = nodeTo.(CilSsaDefinitionExtNode).getDefinition()
|
||||
)
|
||||
or
|
||||
// Flow from SSA definition to first read
|
||||
def = nodeFrom.(CilSsaDefinitionExtNode).getDefinition() and
|
||||
nodeTo = TCilExprNode(CilSsaImpl::getAFirstReadExt(def))
|
||||
or
|
||||
// Flow from read to next read
|
||||
exists(CIL::ReadAccess readFrom, CIL::ReadAccess readTo |
|
||||
CilSsaImpl::hasAdjacentReadsExt(def, readFrom, readTo) and
|
||||
nodeTo = TCilExprNode(readTo) and
|
||||
nodeFrom = TCilExprNode(readFrom) and
|
||||
nodeFrom != nodeTo
|
||||
)
|
||||
or
|
||||
// Flow into phi (read) node
|
||||
exists(CilSsaImpl::DefinitionExt phi |
|
||||
localFlowCilSsaInput(nodeFrom, def, phi) and
|
||||
phi = nodeTo.(CilSsaDefinitionExtNode).getDefinition()
|
||||
|
|
||||
phi instanceof CilSsa::PhiNode
|
||||
or
|
||||
phi instanceof CilSsaImpl::PhiReadNode
|
||||
)
|
||||
}
|
||||
|
||||
private predicate localExactStep(CIL::DataFlowNode src, CIL::DataFlowNode sink) {
|
||||
src = sink.(CIL::Opcodes::Dup).getAnOperand()
|
||||
or
|
||||
src = sink.(CIL::Conversion).getExpr()
|
||||
or
|
||||
src = sink.(CIL::WriteAccess).getExpr()
|
||||
or
|
||||
src = sink.(CIL::Method).getAnImplementation().getAnInstruction().(CIL::Return)
|
||||
or
|
||||
src = sink.(CIL::Return).getExpr()
|
||||
or
|
||||
src = sink.(CIL::ConditionalBranch).getAnOperand()
|
||||
}
|
||||
|
||||
predicate localFlowStepCil(Node nodeFrom, Node nodeTo) {
|
||||
localExactStep(asCilDataFlowNode(nodeFrom), asCilDataFlowNode(nodeTo))
|
||||
or
|
||||
localCilSsaFlowStep(_, nodeFrom, nodeTo)
|
||||
}
|
||||
}
|
||||
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
hasNodePath(any(LocalExprStepConfiguration x), nodeFrom, nodeTo)
|
||||
or
|
||||
@@ -812,8 +720,6 @@ module LocalFlow {
|
||||
or
|
||||
ThisFlow::adjacentThisRefs(nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
|
||||
or
|
||||
CilFlow::localFlowStepCil(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(AssignableDefinition def, ControlFlow::Node cfn, Ssa::ExplicitDefinition ssaDef |
|
||||
ssaDef.getADefinition() = def and
|
||||
ssaDef.getControlFlowNode() = cfn and
|
||||
@@ -1115,13 +1021,6 @@ private predicate arrayStore(Expr e, Expr src, Expr a, boolean postUpdate) {
|
||||
*/
|
||||
private predicate arrayRead(Expr e1, ArrayRead e2) { e1 = e2.getQualifier() }
|
||||
|
||||
private Type getCSharpType(DotNet::Type t) {
|
||||
result = t
|
||||
or
|
||||
not t instanceof Type and
|
||||
result.matchesHandle(t)
|
||||
}
|
||||
|
||||
private class RelevantGvnType extends Gvn::GvnType {
|
||||
RelevantGvnType() { this = any(NodeImpl n).getDataFlowType().asGvnType() }
|
||||
}
|
||||
@@ -1193,8 +1092,6 @@ private module Cached {
|
||||
cached
|
||||
newtype TNode =
|
||||
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getAstNode() instanceof Expr } or
|
||||
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
|
||||
TCilSsaDefinitionExtNode(CilSsaImpl::DefinitionExt def) or
|
||||
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) {
|
||||
// Handled by `TExplicitParameterNode` below
|
||||
not def.(Ssa::ExplicitDefinition).getADefinition() instanceof
|
||||
@@ -1205,7 +1102,7 @@ private module Cached {
|
||||
// Handled by `TExplicitParameterNode` below
|
||||
not def instanceof AssignableDefinitions::ImplicitParameterDefinition
|
||||
} or
|
||||
TExplicitParameterNode(DotNet::Parameter p) {
|
||||
TExplicitParameterNode(Parameter p) {
|
||||
p = any(DataFlowCallable dfc).asCallable().getAParameter()
|
||||
} or
|
||||
TInstanceParameterNode(InstanceCallable c) or
|
||||
@@ -1375,28 +1272,6 @@ predicate nodeIsHidden(Node n) {
|
||||
n instanceof CaptureNode
|
||||
}
|
||||
|
||||
/** A CIL SSA definition, viewed as a node in a data flow graph. */
|
||||
class CilSsaDefinitionExtNode extends NodeImpl, TCilSsaDefinitionExtNode {
|
||||
CilSsaImpl::DefinitionExt def;
|
||||
|
||||
CilSsaDefinitionExtNode() { this = TCilSsaDefinitionExtNode(def) }
|
||||
|
||||
/** Gets the underlying SSA definition. */
|
||||
CilSsaImpl::DefinitionExt getDefinition() { result = def }
|
||||
|
||||
override DataFlowCallable getEnclosingCallableImpl() {
|
||||
result.asCallable() = def.getBasicBlock().getFirstNode().getImplementation().getMethod()
|
||||
}
|
||||
|
||||
override CIL::Type getTypeImpl() { result = def.getSourceVariable().getType() }
|
||||
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
override Location getLocationImpl() { result = def.getBasicBlock().getLocation() }
|
||||
|
||||
override string toStringImpl() { result = def.toString() }
|
||||
}
|
||||
|
||||
/** An SSA definition, viewed as a node in a data flow graph. */
|
||||
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
|
||||
SsaImpl::DefinitionExt def;
|
||||
@@ -1468,7 +1343,7 @@ private module ParameterNodes {
|
||||
* flow graph.
|
||||
*/
|
||||
class ExplicitParameterNode extends ParameterNodeImpl, TExplicitParameterNode {
|
||||
private DotNet::Parameter parameter;
|
||||
private Parameter parameter;
|
||||
|
||||
ExplicitParameterNode() { this = TExplicitParameterNode(parameter) }
|
||||
|
||||
@@ -1486,7 +1361,7 @@ private module ParameterNodes {
|
||||
result.asCallable() = parameter.getCallable()
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() { result = parameter.getType() }
|
||||
override Type getTypeImpl() { result = parameter.getType() }
|
||||
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
@@ -1543,7 +1418,7 @@ private module ParameterNodes {
|
||||
|
||||
override Location getLocationImpl() { result = callable.getLocation() }
|
||||
|
||||
override DotNet::Type getTypeImpl() { none() }
|
||||
override Type getTypeImpl() { none() }
|
||||
|
||||
override DataFlowType getDataFlowType() { callable = result.asDelegate() }
|
||||
|
||||
@@ -1612,11 +1487,7 @@ private module ArgumentNodes {
|
||||
|
||||
/** A data-flow node that represents an explicit call argument. */
|
||||
class ExplicitArgumentNode extends ArgumentNodeImpl {
|
||||
ExplicitArgumentNode() {
|
||||
this.asExpr() instanceof Argument
|
||||
or
|
||||
this.asExpr() = any(CilDataFlowCall cc).getCilCall().getAnArgument()
|
||||
}
|
||||
ExplicitArgumentNode() { this.asExpr() instanceof Argument }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
exists(ArgumentConfiguration x, Expr c, Argument arg |
|
||||
@@ -1625,12 +1496,6 @@ private module ArgumentNodes {
|
||||
arg.isArgumentOf(c, pos) and
|
||||
x.hasExprPath(_, this.getControlFlowNode(), _, call.getControlFlowNode())
|
||||
)
|
||||
or
|
||||
exists(CIL::Call c, CIL::Expr arg |
|
||||
arg = this.asExpr() and
|
||||
c = call.getExpr() and
|
||||
arg = c.getArgument(pos.getPosition())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1747,7 +1612,7 @@ private module ReturnNodes {
|
||||
*/
|
||||
class ExprReturnNode extends ReturnNode, ExprNode {
|
||||
ExprReturnNode() {
|
||||
exists(DotNet::Callable c, DotNet::Expr e | e = this.getExpr() |
|
||||
exists(Callable c, Expr e | e = this.getExpr() |
|
||||
c.canReturn(e) and not c.(Modifiable).isAsync()
|
||||
)
|
||||
}
|
||||
@@ -1881,17 +1746,13 @@ private module OutNodes {
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that reads a value returned directly by a callable,
|
||||
* either via a C# call or a CIL call.
|
||||
* A data-flow node that reads a value returned directly by a callable.
|
||||
*/
|
||||
class ExprOutNode extends OutNode, ExprNode {
|
||||
private DataFlowCall call;
|
||||
|
||||
ExprOutNode() {
|
||||
exists(DotNet::Expr e | e = this.getExpr() |
|
||||
call = csharpCall(e, this.getControlFlowNode()) or
|
||||
call = TCilCall(e)
|
||||
)
|
||||
exists(Expr e | e = this.getExpr() | call = csharpCall(e, this.getControlFlowNode()))
|
||||
}
|
||||
|
||||
override DataFlowCall getCall(ReturnKind kind) {
|
||||
@@ -1973,7 +1834,7 @@ class FlowSummaryNode extends NodeImpl, TFlowSummaryNode {
|
||||
result = FlowSummaryImpl::Private::summaryNodeType(this.getSummaryNode())
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() { none() }
|
||||
override Type getTypeImpl() { none() }
|
||||
|
||||
override ControlFlow::Node getControlFlowNodeImpl() { none() }
|
||||
|
||||
@@ -2134,8 +1995,6 @@ class FieldOrProperty extends Assignable, Modifiable {
|
||||
or
|
||||
p.isAutoImplementedReadOnly()
|
||||
or
|
||||
p.matchesHandle(any(CIL::TrivialProperty tp))
|
||||
or
|
||||
p.getDeclaringType() instanceof AnonymousClass
|
||||
)
|
||||
)
|
||||
@@ -2740,7 +2599,7 @@ module PostUpdateNodes {
|
||||
result = getEnclosingStaticFieldOrProperty(oc)
|
||||
}
|
||||
|
||||
override DotNet::Type getTypeImpl() { result = oc.getType() }
|
||||
override Type getTypeImpl() { result = oc.getType() }
|
||||
|
||||
override ControlFlow::Nodes::ElementNode getControlFlowNodeImpl() { result = cfn }
|
||||
|
||||
@@ -2853,7 +2712,7 @@ class CastNode extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowExpr = DotNet::Expr;
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
|
||||
private predicate constantBooleanExpr(Expr e, boolean val) {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
private import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
private import DataFlowDispatch
|
||||
private import DataFlowPrivate
|
||||
private import semmle.code.csharp.controlflow.Guards
|
||||
@@ -12,7 +10,7 @@ private import semmle.code.csharp.Unification
|
||||
*/
|
||||
class Node extends TNode {
|
||||
/** Gets the expression corresponding to this node, if any. */
|
||||
DotNet::Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
Expr asExpr() { result = this.(ExprNode).getExpr() }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, at control flow node `cfn`,
|
||||
@@ -23,7 +21,7 @@ class Node extends TNode {
|
||||
}
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
DotNet::Parameter asParameter() { result = this.(ParameterNode).getParameter() }
|
||||
Parameter asParameter() { result = this.(ParameterNode).getParameter() }
|
||||
|
||||
/** Gets the definition corresponding to this node, if any. */
|
||||
AssignableDefinition asDefinition() { result = this.asDefinitionAtNode(_) }
|
||||
@@ -37,7 +35,7 @@ class Node extends TNode {
|
||||
}
|
||||
|
||||
/** Gets the type of this node. */
|
||||
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
|
||||
final Type getType() { result = this.(NodeImpl).getTypeImpl() }
|
||||
|
||||
/** Gets the enclosing callable of this node. */
|
||||
final Callable getEnclosingCallable() {
|
||||
@@ -67,8 +65,6 @@ class Node extends TNode {
|
||||
}
|
||||
}
|
||||
|
||||
private class TExprNode_ = TExprNode or TCilExprNode;
|
||||
|
||||
/**
|
||||
* An expression, viewed as a node in a data flow graph.
|
||||
*
|
||||
@@ -76,13 +72,9 @@ private class TExprNode_ = TExprNode or TCilExprNode;
|
||||
* to multiple `ExprNode`s, just like it may correspond to multiple
|
||||
* `ControlFlow::Node`s.
|
||||
*/
|
||||
class ExprNode extends Node, TExprNode_ {
|
||||
class ExprNode extends Node, TExprNode {
|
||||
/** Gets the expression corresponding to this node. */
|
||||
DotNet::Expr getExpr() {
|
||||
result = this.getExprAtNode(_)
|
||||
or
|
||||
this = TCilExprNode(result)
|
||||
}
|
||||
Expr getExpr() { result = this.getExprAtNode(_) }
|
||||
|
||||
/**
|
||||
* Gets the expression corresponding to this node, at control flow node `cfn`,
|
||||
@@ -100,7 +92,7 @@ class ExprNode extends Node, TExprNode_ {
|
||||
*/
|
||||
class ParameterNode extends Node instanceof ParameterNodeImpl {
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
DotNet::Parameter getParameter() {
|
||||
Parameter getParameter() {
|
||||
exists(DataFlowCallable c, ParameterPosition ppos |
|
||||
super.isParameterOf(c, ppos) and
|
||||
result = c.asCallable().getParameter(ppos.getPosition())
|
||||
@@ -120,12 +112,12 @@ class AssignableDefinitionNode extends Node instanceof AssignableDefinitionNodeI
|
||||
}
|
||||
|
||||
/** Gets a node corresponding to expression `e`. */
|
||||
ExprNode exprNode(DotNet::Expr e) { result.getExpr() = e }
|
||||
ExprNode exprNode(Expr e) { result.getExpr() = e }
|
||||
|
||||
/**
|
||||
* Gets the node corresponding to the value of parameter `p` at function entry.
|
||||
*/
|
||||
ParameterNode parameterNode(DotNet::Parameter p) { result.getParameter() = p }
|
||||
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
|
||||
/** Gets a node corresponding to the definition `def`. */
|
||||
AssignableDefinitionNode assignableDefinitionNode(AssignableDefinition def) {
|
||||
@@ -146,7 +138,7 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
|
||||
* local (intra-procedural) steps.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate localExprFlow(DotNet::Expr e1, DotNet::Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
|
||||
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
|
||||
|
||||
/**
|
||||
* A data flow node that jumps between callables. This can be extended in
|
||||
|
||||
@@ -7,8 +7,6 @@ private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.dataflow.internal.ControlFlowReachability
|
||||
private import semmle.code.csharp.dispatch.Dispatch
|
||||
private import semmle.code.csharp.commons.ComparisonTest
|
||||
private import cil
|
||||
private import dotnet
|
||||
// import `TaintedMember` definitions from other files to avoid potential reevaluation
|
||||
private import semmle.code.csharp.frameworks.JsonNET
|
||||
private import semmle.code.csharp.frameworks.WCF
|
||||
@@ -33,16 +31,6 @@ predicate defaultTaintSanitizer(DataFlow::Node node) {
|
||||
bindingset[node]
|
||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) { none() }
|
||||
|
||||
private predicate localCilTaintStep(CIL::DataFlowNode src, CIL::DataFlowNode sink) {
|
||||
src = sink.(CIL::BinaryArithmeticExpr).getAnOperand() or
|
||||
src = sink.(CIL::Opcodes::Neg).getOperand() or
|
||||
src = sink.(CIL::UnaryBitwiseOperation).getOperand()
|
||||
}
|
||||
|
||||
private predicate localTaintStepCil(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
localCilTaintStep(asCilDataFlowNode(nodeFrom), asCilDataFlowNode(nodeTo))
|
||||
}
|
||||
|
||||
private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityConfiguration {
|
||||
LocalTaintExprStepConfiguration() { this = "LocalTaintExprStepConfiguration" }
|
||||
|
||||
@@ -106,8 +94,6 @@ private class LocalTaintExprStepConfiguration extends ControlFlowReachabilityCon
|
||||
|
||||
private predicate localTaintStepCommon(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
hasNodePath(any(LocalTaintExprStepConfiguration x), nodeFrom, nodeTo)
|
||||
or
|
||||
localTaintStepCil(nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
cached
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
private import cil
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A run-time callable. That is, a callable that is neither abstract
|
||||
* nor defined in an interface.
|
||||
*/
|
||||
class RuntimeCallable extends DotNet::Callable {
|
||||
class RuntimeCallable extends Callable {
|
||||
RuntimeCallable() {
|
||||
not this.(Modifiable).isAbstract() and
|
||||
(
|
||||
@@ -24,13 +22,10 @@ class RuntimeCallable extends DotNet::Callable {
|
||||
|
||||
/** A run-time method. */
|
||||
class RuntimeMethod extends RuntimeCallable {
|
||||
RuntimeMethod() {
|
||||
this instanceof Method or
|
||||
this instanceof CIL::Method
|
||||
}
|
||||
RuntimeMethod() { this instanceof Method }
|
||||
|
||||
/** Holds if the method is `static`. */
|
||||
predicate isStatic() { this.(Method).isStatic() or this.(CIL::Method).isStatic() }
|
||||
predicate isStatic() { this.(Method).isStatic() }
|
||||
}
|
||||
|
||||
/** A run-time instance method. */
|
||||
|
||||
@@ -64,7 +64,7 @@ class Call extends Expr, @call {
|
||||
* consider default arguments.
|
||||
*/
|
||||
cached
|
||||
Expr getArgumentForParameter(DotNet::Parameter p) {
|
||||
Expr getArgumentForParameter(Parameter p) {
|
||||
// Appears in the positional part of the call
|
||||
result = this.getImplicitArgument(p)
|
||||
or
|
||||
@@ -74,7 +74,7 @@ class Call extends Expr, @call {
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private Expr getImplicitArgument(DotNet::Parameter p) {
|
||||
private Expr getImplicitArgument(Parameter p) {
|
||||
this.getTarget().getAParameter() = p and
|
||||
not exists(result.getExplicitArgumentName()) and
|
||||
(
|
||||
|
||||
@@ -18,7 +18,6 @@ import semmle.code.csharp.controlflow.ControlFlowElement
|
||||
import semmle.code.csharp.Location
|
||||
import semmle.code.csharp.Stmt
|
||||
import semmle.code.csharp.Type
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
private import semmle.code.csharp.frameworks.System
|
||||
private import semmle.code.csharp.TypeRef
|
||||
@@ -950,13 +949,13 @@ class InterpolatedStringExpr extends Expr, @interpolated_string_expr {
|
||||
* A `throw` element. Either a `throw` expression (`ThrowExpr`)
|
||||
* or a `throw` statement (`ThrowStmt`).
|
||||
*/
|
||||
class ThrowElement extends ControlFlowElement, DotNet::Throw, @throw_element {
|
||||
class ThrowElement extends ControlFlowElement, @throw_element {
|
||||
/**
|
||||
* Gets the expression of the exception being thrown, if any.
|
||||
*
|
||||
* For example, `new Exception("Syntax error")` in `throw new Exception("Syntax error");`.
|
||||
*/
|
||||
override Expr getExpr() { result = this.getChild(0) }
|
||||
Expr getExpr() { result = this.getChild(0) }
|
||||
|
||||
/** Gets the type of exception being thrown. */
|
||||
Class getThrownExceptionType() {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import Expr
|
||||
private import dotnet
|
||||
|
||||
/**
|
||||
* A literal. Either a Boolean literal (`BoolLiteral`), a Unicode character
|
||||
@@ -13,7 +12,7 @@ private import dotnet
|
||||
* point literal (`RealLiteral`), a `string` literal (`StringLiteral`), or a
|
||||
* `null` literal (`NullLiteral`).
|
||||
*/
|
||||
class Literal extends DotNet::Literal, Expr, @literal_expr {
|
||||
class Literal extends Expr, @literal_expr {
|
||||
override string toString() { result = this.getValue() }
|
||||
}
|
||||
|
||||
@@ -43,7 +42,7 @@ class CharLiteral extends Literal, @char_literal_expr {
|
||||
* literal (`LongLiteral`), a `uint` literal (`UIntLiteral`), or a `ulong`
|
||||
* literal (`ULongLiteral`).
|
||||
*/
|
||||
class IntegerLiteral extends DotNet::IntLiteral, Literal, @integer_literal_expr { }
|
||||
class IntegerLiteral extends Literal, @integer_literal_expr { }
|
||||
|
||||
/**
|
||||
* An `int` literal, for example `0`.
|
||||
@@ -105,7 +104,7 @@ class DecimalLiteral extends RealLiteral, @decimal_literal_expr {
|
||||
* A `string` literal. Either a `string` literal (`StringLiteralUtf16`),
|
||||
* or a `u8` literal (`StringLiteralUtf8`).
|
||||
*/
|
||||
class StringLiteral extends DotNet::StringLiteral, Literal, @string_literal_expr {
|
||||
class StringLiteral extends Literal, @string_literal_expr {
|
||||
override string toString() { result = "\"" + this.getValue().replaceAll("\"", "\\\"") + "\"" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "StringLiteral" }
|
||||
@@ -128,6 +127,6 @@ class StringLiteralUtf8 extends StringLiteral, @utf8_string_literal_expr {
|
||||
/**
|
||||
* A `null` literal.
|
||||
*/
|
||||
class NullLiteral extends DotNet::NullLiteral, Literal, @null_literal_expr {
|
||||
class NullLiteral extends Literal, @null_literal_expr {
|
||||
override string getAPrimaryQlClass() { result = "NullLiteral" }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import csharp
|
||||
private import dotnet
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isTestNamespace(Namespace ns) {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
*/
|
||||
|
||||
private import csharp as CS
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections as Collections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
@@ -62,7 +61,7 @@ predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1;
|
||||
* In the Standard library and 3rd party libraries it the callables that can be called
|
||||
* from outside the library itself.
|
||||
*/
|
||||
class TargetApiSpecific extends DotNet::Callable {
|
||||
class TargetApiSpecific extends CS::Callable {
|
||||
TargetApiSpecific() {
|
||||
this.fromSource() and
|
||||
this.isUnboundDeclaration()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
private import csharp
|
||||
private import dotnet
|
||||
private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||
@@ -21,14 +20,14 @@ private predicate genericCollectionType(ValueOrRefType t, TypeParameter tp) {
|
||||
/**
|
||||
* Holds if `tp` is a type parameter of the immediate type declaring `callable`.
|
||||
*/
|
||||
private predicate classTypeParameter(DotNet::Callable callable, TypeParameter tp) {
|
||||
private predicate classTypeParameter(Callable callable, TypeParameter tp) {
|
||||
callable.getDeclaringType().(UnboundGeneric).getATypeParameter() = tp
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `tp` is type parameter of `callable` or the type declaring `callable`.
|
||||
*/
|
||||
private predicate localTypeParameter(DotNet::Callable callable, TypeParameter tp) {
|
||||
private predicate localTypeParameter(Callable callable, TypeParameter tp) {
|
||||
classTypeParameter(callable, tp) or
|
||||
callable.(UnboundGeneric).getATypeParameter() = tp
|
||||
}
|
||||
@@ -37,7 +36,7 @@ private predicate localTypeParameter(DotNet::Callable callable, TypeParameter tp
|
||||
* Holds if `callable` has a parameter of type `tp`
|
||||
* or collection parameterized over type `tp`.
|
||||
*/
|
||||
private predicate parameter(DotNet::Callable callable, string input, TypeParameter tp) {
|
||||
private predicate parameter(Callable callable, string input, TypeParameter tp) {
|
||||
exists(Parameter p |
|
||||
input = Specific::parameterAccess(p) and
|
||||
p = callable.getAParameter() and
|
||||
@@ -62,7 +61,7 @@ private string getSyntheticField(TypeParameter tp) {
|
||||
* Gets a models as data string representation of, how a value of type `tp`
|
||||
* can be read or stored implicitly in relation to `callable`.
|
||||
*/
|
||||
private string implicit(DotNet::Callable callable, TypeParameter tp) {
|
||||
private string implicit(Callable callable, TypeParameter tp) {
|
||||
classTypeParameter(callable, tp) and
|
||||
not callable.(Modifiable).isStatic() and
|
||||
exists(string access |
|
||||
@@ -77,7 +76,7 @@ private string implicit(DotNet::Callable callable, TypeParameter tp) {
|
||||
/**
|
||||
* Holds if `callable` has a delegate parameter `dt` at parameter position `position`.
|
||||
*/
|
||||
private predicate delegate(DotNet::Callable callable, DelegateType dt, int position) {
|
||||
private predicate delegate(Callable callable, DelegateType dt, int position) {
|
||||
exists(Parameter p |
|
||||
p = callable.getAParameter() and
|
||||
dt = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() and
|
||||
@@ -93,7 +92,7 @@ private predicate delegate(DotNet::Callable callable, DelegateType dt, int posit
|
||||
* in every disjunction.
|
||||
*/
|
||||
bindingset[callable]
|
||||
private string getAccess(DotNet::Callable callable, Type return, TypeParameter tp) {
|
||||
private string getAccess(Callable callable, Type return, TypeParameter tp) {
|
||||
return = tp and result = ""
|
||||
or
|
||||
genericCollectionType(return, tp) and result = ".Element"
|
||||
@@ -111,7 +110,7 @@ private string getAccess(DotNet::Callable callable, Type return, TypeParameter t
|
||||
* Holds if `input` is a models as data string representation of, how a value of type `tp`
|
||||
* (or a generic parameterized over `tp`) can be generated by a delegate parameter of `callable`.
|
||||
*/
|
||||
private predicate delegateSource(DotNet::Callable callable, string input, TypeParameter tp) {
|
||||
private predicate delegateSource(Callable callable, string input, TypeParameter tp) {
|
||||
exists(DelegateType dt, int position, Type return, string access |
|
||||
delegate(callable, dt, position) and
|
||||
return = dt.getReturnType() and
|
||||
@@ -129,7 +128,7 @@ private predicate delegateSource(DotNet::Callable callable, string input, TypePa
|
||||
* (2) The parameters of `callable`.
|
||||
* (3) Any delegate parameters of `callable`.
|
||||
*/
|
||||
private predicate input(DotNet::Callable callable, string input, TypeParameter tp) {
|
||||
private predicate input(Callable callable, string input, TypeParameter tp) {
|
||||
input = implicit(callable, tp)
|
||||
or
|
||||
parameter(callable, input, tp)
|
||||
@@ -141,7 +140,7 @@ private predicate input(DotNet::Callable callable, string input, TypeParameter t
|
||||
* Holds if `callable` returns a value of type `tp` (or a generic parameterized over `tp`) and `output`
|
||||
* is a models as data string representation of, how data is routed to the return.
|
||||
*/
|
||||
private predicate returns(DotNet::Callable callable, TypeParameter tp, string output) {
|
||||
private predicate returns(Callable callable, TypeParameter tp, string output) {
|
||||
exists(Type return, string access | return = callable.getReturnType() |
|
||||
access = getAccess(callable, return, tp) and
|
||||
output = "ReturnValue" + access
|
||||
@@ -153,7 +152,7 @@ private predicate returns(DotNet::Callable callable, TypeParameter tp, string ou
|
||||
* and `output` is the models as data string representation of, how data is routed to
|
||||
* the delegate parameter.
|
||||
*/
|
||||
private predicate delegateSink(DotNet::Callable callable, TypeParameter tp, string output) {
|
||||
private predicate delegateSink(Callable callable, TypeParameter tp, string output) {
|
||||
exists(DelegateType dt, int position, Parameter p |
|
||||
delegate(callable, dt, position) and
|
||||
p = dt.getAParameter() and
|
||||
@@ -170,7 +169,7 @@ private predicate delegateSink(DotNet::Callable callable, TypeParameter tp, stri
|
||||
* (2) The return of `callable`.
|
||||
* (3) Any delegate parameters of `callable`.
|
||||
*/
|
||||
private predicate output(DotNet::Callable callable, TypeParameter tp, string output) {
|
||||
private predicate output(Callable callable, TypeParameter tp, string output) {
|
||||
output = implicit(callable, tp)
|
||||
or
|
||||
returns(callable, tp, output)
|
||||
|
||||
Reference in New Issue
Block a user