-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathBadDynamicCall.ql
More file actions
109 lines (98 loc) · 4.09 KB
/
BadDynamicCall.ql
File metadata and controls
109 lines (98 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/**
* @name Bad dynamic call
* @description The type of the target of a dynamic invocation expression must have a method or operator with the appropriate signature, or an exception will be thrown.
* @kind problem
* @problem.severity error
* @precision medium
* @id cs/invalid-dynamic-call
* @tags quality
* reliability
* correctness
* external/cwe/cwe-628
*/
import csharp
import semmle.code.csharp.dispatch.Dispatch
abstract class BadDynamicCall extends DynamicExpr {
abstract predicate isBad(Variable v, ValueOrRefType pt, Expr pts, string message, string target);
abstract AssignableRead getARelevantVariableAccess(int i);
Type possibleBadTypeForRelevantSource(Variable v, int i, Expr source) {
exists(Type t | t = this.possibleTypeForRelevantSource(v, i, source) |
// If the source can have the type of an interface or an abstract class,
// then all possible sub types are, in principle, possible
t instanceof Interface and result.isImplicitlyConvertibleTo(t)
or
t.(Class).isAbstract() and result.isImplicitlyConvertibleTo(t)
or
result = t
) and
not result instanceof Interface and
not result.(Class).isAbstract() and
not result instanceof NullType and
not result instanceof DynamicType
}
private Type possibleTypeForRelevantSource(Variable v, int i, Expr source) {
exists(AssignableRead read, Ssa::Definition ssaDef, Ssa::ExplicitDefinition ultimateSsaDef |
read = this.getARelevantVariableAccess(i) and
v = read.getTarget() and
result = source.getType() and
read = ssaDef.getARead() and
ultimateSsaDef = ssaDef.getAnUltimateDefinition()
|
ultimateSsaDef.getADefinition() =
any(AssignableDefinition def | source = def.getSource().stripImplicit())
or
ultimateSsaDef.getADefinition() =
any(AssignableDefinitions::ImplicitParameterDefinition p |
source = p.getParameter().getAnAssignedValue().stripImplicit()
)
)
}
}
class BadDynamicMethodCall extends BadDynamicCall, DynamicMethodCall {
override AssignableRead getARelevantVariableAccess(int i) {
result = this.getQualifier() and i = -1
}
override predicate isBad(Variable v, ValueOrRefType pt, Expr pts, string message, string target) {
pt = this.possibleBadTypeForRelevantSource(v, -1, pts) and
not exists(Method m | m = this.getARuntimeTarget() |
pt.isImplicitlyConvertibleTo(m.getDeclaringType())
) and
message =
"The $@ of this dynamic method invocation can obtain (from $@) type $@, which does not have a method '"
+ this.getLateBoundTargetName() + "' with the appropriate signature." and
target = "target"
}
}
class BadDynamicOperatorCall extends BadDynamicCall, DynamicOperatorCall {
override AssignableRead getARelevantVariableAccess(int i) { result = this.getRuntimeArgument(i) }
override predicate isBad(Variable v, ValueOrRefType pt, Expr pts, string message, string target) {
exists(int i |
pt = this.possibleBadTypeForRelevantSource(v, i, pts) and
not pt.containsTypeParameters() and
not exists(Type paramType | paramType = this.getADynamicParameterType(_, i) |
pt.isImplicitlyConvertibleTo(paramType)
or
// If either the argument type or the parameter type contains type parameters,
// then assume they may match
paramType.containsTypeParameters()
) and
exists(string number |
number = "first" and i = 0
or
number = "second" and i = 1
|
target = number + " argument"
)
) and
message =
"The $@ of this dynamic operator can obtain (from $@) type $@, which does not match an operator '"
+ this.getLateBoundTargetName() + "' with the appropriate signature."
}
private Type getADynamicParameterType(Operator o, int i) {
o = this.getARuntimeTarget() and
result = o.getParameter(i).getType()
}
}
from BadDynamicCall call, Variable v, ValueOrRefType pt, Expr pts, string message, string target
where call.isBad(v, pt, pts, message, target)
select call, message, v, target, pts, "here", pt, pt.getName()