Skip to content

Commit 56efe3a

Browse files
Fix false positive result.
1 parent 5fc056b commit 56efe3a

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

python/ql/src/Expressions/HashedButNoHash.ql

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import python
1616
* For sequences, the index must be an int, which are hashable, so we don't need to treat them specially.
1717
* For numpy arrays, the index may be a list, which are not hashable and needs to be treated specially.
1818
*/
19-
19+
2020
predicate numpy_array_type(ClassObject na) {
2121
exists(ModuleObject np | np.getName() = "numpy" or np.getName() = "numpy.core" |
2222
na.getAnImproperSuperType() = np.getAttribute("ndarray")
@@ -51,9 +51,31 @@ predicate is_unhashable(ControlFlowNode f, ClassObject cls, ControlFlowNode orig
5151
)
5252
}
5353

54+
/**
55+
* Holds if `f` is inside a `try` that catches `TypeError`. For example:
56+
*
57+
* try:
58+
* ... f ...
59+
* except TypeError:
60+
* ...
61+
*
62+
* This predicate is used to eliminate false positive results. If `hash`
63+
* is called on an unhashable object then a `TypeError` will be thrown.
64+
* But this is not a bug if the code catches the `TypeError` and handles
65+
* it.
66+
*/
67+
predicate typeerror_is_caught(ControlFlowNode f) {
68+
exists (Try try, CheckClass c |
69+
try.getBody().contains(f.getNode()) and
70+
c.getName() = "TypeError" and
71+
try.getAHandler().getType().refersTo(c))
72+
}
73+
5474
from ControlFlowNode f, ClassObject c, ControlFlowNode origin
55-
where
56-
explicitly_hashed(f) and is_unhashable(f, c, origin)
57-
or
58-
unhashable_subscript(f, c, origin)
75+
where
76+
not typeerror_is_caught(f)
77+
and
78+
(explicitly_hashed(f) and is_unhashable(f, c, origin)
79+
or
80+
unhashable_subscript(f, c, origin))
5981
select f.getNode(), "This $@ of $@ is unhashable.", origin, "instance", c, c.getQualifiedName()

0 commit comments

Comments
 (0)