-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathObjectComparison.ql
67 lines (62 loc) · 2.39 KB
/
ObjectComparison.ql
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
/**
* @name Reference equality test on System.Object
* @description Comparisons ('==' or '!=') between something of type 'System.Object' and something of another
* type will use reference comparison, which may not have been what was intended.
* @kind problem
* @problem.severity warning
* @precision medium
* @id cs/reference-equality-with-object
* @tags reliability
* correctness
* external/cwe/cwe-595
*/
import csharp
import semmle.code.csharp.frameworks.System
Expr getObjectOperand(EqualityOperation eq) {
result = eq.getAnOperand() and
(
result.getType() instanceof ObjectType or
result.getType() instanceof Interface
)
}
class ReferenceEqualityTestOnObject extends EqualityOperation {
ReferenceEqualityTestOnObject() {
// One or both of the operands has type object or interface.
exists(getObjectOperand(this)) and
// Neither operand is 'null'.
not this.getAnOperand() instanceof NullLiteral and
not exists(Type t | t = this.getAnOperand().stripImplicit().getType() |
t instanceof NullType or
t instanceof ValueType
) and
// Neither operand is a constant - a reference comparison may well be intended for those.
not this.getAnOperand().(FieldAccess).getTarget().isReadOnly() and
not this.getAnOperand().hasValue() and
// Not a short-cut test in a custom `Equals` method
not exists(EqualsMethod m |
this.getEnclosingCallable() = m and
this.getAnOperand() instanceof ThisAccess and
this.getAnOperand() = m.getParameter(0).getAnAccess()
) and
// Reference comparisons in Moq methods are used to define mocks
not exists(MethodCall mc, Namespace n |
mc.getTarget().getDeclaringType().getNamespace().getParentNamespace*() = n and
n.hasName("Moq") and
not exists(n.getParentNamespace()) and
mc.getAnArgument() = this.getEnclosingCallable()
)
}
Expr getObjectOperand() {
result = getObjectOperand(this) and
// Avoid duplicate results: only include left operand if both operands
// have object type
(result = this.getRightOperand() implies not this.getLeftOperand() = getObjectOperand(this))
}
}
from ReferenceEqualityTestOnObject scw, Expr operand, Type t
where
operand = scw.getObjectOperand() and
t = operand.getType()
select scw,
"Reference equality for System.Object comparisons ($@ argument has type " + t.getName() + ").",
operand, "this"