Skip to content

Commit 271f32e

Browse files
Move missing/multiple calls to init/del queries to folder
1 parent 23b9db8 commit 271f32e

16 files changed

+79
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
deprecated module;
2+
3+
import python
4+
5+
// Helper predicates for multiple call to __init__/__del__ queries.
6+
pragma[noinline]
7+
private predicate multiple_invocation_paths_helper(
8+
FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi
9+
) {
10+
i1 != i2 and
11+
i1 = top.getACallee+() and
12+
i2 = top.getACallee+() and
13+
i1.getFunction() = multi
14+
}
15+
16+
pragma[noinline]
17+
private predicate multiple_invocation_paths(
18+
FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2, FunctionObject multi
19+
) {
20+
multiple_invocation_paths_helper(top, i1, i2, multi) and
21+
i2.getFunction() = multi
22+
}
23+
24+
/** Holds if `self.name` calls `multi` by multiple paths, and thus calls it more than once. */
25+
predicate multiple_calls_to_superclass_method(ClassObject self, FunctionObject multi, string name) {
26+
exists(FunctionInvocation top, FunctionInvocation i1, FunctionInvocation i2 |
27+
multiple_invocation_paths(top, i1, i2, multi) and
28+
top.runtime(self.declaredAttribute(name)) and
29+
self.getASuperType().declaredAttribute(name) = multi
30+
|
31+
// Only called twice if called from different functions,
32+
// or if one call-site can reach the other.
33+
i1.getCall().getScope() != i2.getCall().getScope()
34+
or
35+
i1.getCall().strictlyReaches(i2.getCall())
36+
)
37+
}
38+
39+
/** Holds if all attributes called `name` can be inferred to be methods. */
40+
private predicate named_attributes_not_method(ClassObject cls, string name) {
41+
cls.declaresAttribute(name) and not cls.declaredAttribute(name) instanceof FunctionObject
42+
}
43+
44+
/** Holds if `f` actually does something. */
45+
private predicate does_something(FunctionObject f) {
46+
f.isBuiltin() and not f = theObjectType().lookupAttribute("__init__")
47+
or
48+
exists(Stmt s | s = f.getFunction().getAStmt() and not s instanceof Pass)
49+
}
50+
51+
/** Holds if `meth` looks like it should have a call to `name`, but does not */
52+
private predicate missing_call(FunctionObject meth, string name) {
53+
exists(CallNode call, AttrNode attr |
54+
call.getScope() = meth.getFunction() and
55+
call.getFunction() = attr and
56+
attr.getName() = name and
57+
not exists(FunctionObject f | f.getACall() = call)
58+
)
59+
}
60+
61+
/** Holds if `self.name` does not call `missing`, even though it is expected to. */
62+
predicate missing_call_to_superclass_method(
63+
ClassObject self, FunctionObject top, FunctionObject missing, string name
64+
) {
65+
missing = self.getASuperType().declaredAttribute(name) and
66+
top = self.lookupAttribute(name) and
67+
/* There is no call to missing originating from top */
68+
not top.getACallee*() = missing and
69+
/* Make sure that all named 'methods' are objects that we can understand. */
70+
not exists(ClassObject sup |
71+
sup = self.getAnImproperSuperType() and
72+
named_attributes_not_method(sup, name)
73+
) and
74+
not self.isAbstract() and
75+
does_something(missing) and
76+
not missing_call(top, name)
77+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

python/ql/src/Classes/SuperclassDelCalledMultipleTimes.py renamed to python/ql/src/Classes/CallsToInitDel/SuperclassDelCalledMultipleTimes.py

File renamed without changes.

python/ql/src/Classes/SuperclassDelCalledMultipleTimes.qhelp renamed to python/ql/src/Classes/CallsToInitDel/SuperclassDelCalledMultipleTimes.qhelp

File renamed without changes.

python/ql/src/Classes/SuperclassDelCalledMultipleTimes.ql renamed to python/ql/src/Classes/CallsToInitDel/SuperclassDelCalledMultipleTimes.ql

File renamed without changes.

0 commit comments

Comments
 (0)