Python: Autoformat Resources/ queries

This commit is contained in:
Rasmus Wriedt Larsen
2020-01-22 10:18:07 +01:00
parent 80997a3323
commit 47b932d6ce
2 changed files with 41 additions and 40 deletions

View File

@@ -15,8 +15,10 @@
import python
import FileOpen
/** Whether resource is opened and closed in in a matched pair of methods,
* either __enter__ and __exit__ or __init__ and __del__ */
/**
* Whether resource is opened and closed in in a matched pair of methods,
* either __enter__ and __exit__ or __init__ and __del__
*/
predicate opened_in_enter_closed_in_exit(ControlFlowNode open) {
file_not_closed_at_scope_exit(open) and
exists(FunctionObject entry, FunctionObject exit |
@@ -25,8 +27,7 @@ predicate opened_in_enter_closed_in_exit(ControlFlowNode open) {
cls.declaredAttribute("__enter__") = entry and cls.declaredAttribute("__exit__") = exit
or
cls.declaredAttribute("__init__") = entry and cls.declaredAttribute("__del__") = exit
)
and
) and
exists(AttrNode attr_open, AttrNode attrclose |
attr_open.getScope() = entry.getFunction() and
attrclose.getScope() = exit.getFunction() and
@@ -37,18 +38,19 @@ predicate opened_in_enter_closed_in_exit(ControlFlowNode open) {
)
}
predicate file_not_closed_at_scope_exit(ControlFlowNode open) {
predicate file_not_closed_at_scope_exit(ControlFlowNode open) {
exists(EssaVariable v |
BaseFlow::reaches_exit(v) and
var_is_open(v, open) and
not file_is_returned(v, open)
)
or
call_to_open(open) and not exists(AssignmentDefinition def | def.getValue() = open)
and not exists(Return r | r.getValue() = open.getNode())
call_to_open(open) and
not exists(AssignmentDefinition def | def.getValue() = open) and
not exists(Return r | r.getValue() = open.getNode())
}
predicate file_not_closed_at_exception_exit(ControlFlowNode open, ControlFlowNode exit) {
predicate file_not_closed_at_exception_exit(ControlFlowNode open, ControlFlowNode exit) {
exists(EssaVariable v |
exit.(RaisingNode).viableExceptionalExit(_, _) and
not closes_arg(exit, v.getSourceVariable()) and
@@ -59,14 +61,14 @@ predicate file_not_closed_at_exception_exit(ControlFlowNode open, ControlFlowNod
}
/* Check to see if a file is opened but not closed or returned */
from ControlFlowNode defn, string message
where
not opened_in_enter_closed_in_exit(defn) and
(
file_not_closed_at_scope_exit(defn) and message = "File is opened but is not closed."
or
not file_not_closed_at_scope_exit(defn) and file_not_closed_at_exception_exit(defn, _) and message = "File may not be closed if an exception is raised."
)
not opened_in_enter_closed_in_exit(defn) and
(
file_not_closed_at_scope_exit(defn) and message = "File is opened but is not closed."
or
not file_not_closed_at_scope_exit(defn) and
file_not_closed_at_exception_exit(defn, _) and
message = "File may not be closed if an exception is raised."
)
select defn.getNode(), message

View File

@@ -18,7 +18,8 @@ predicate expr_is_open(ControlFlowNode n, ControlFlowNode open) {
or
exists(EssaVariable v |
n instanceof NameNode and
var_is_open(v, open) |
var_is_open(v, open)
|
n = v.getAUse()
or
wraps_file(n, v)
@@ -46,7 +47,8 @@ predicate passes_open_files(Variable v, ControlFlowNode test, boolean sense) {
exists(AttrNode closed |
closed = test and
closed.getObject("closed") = v.getAUse()
) and sense = false
) and
sense = false
or
// `if fd ==/is ...:` most commonly `if fd is None:`
equality_test(test, v.getAUse(), sense.booleanNot(), _)
@@ -56,29 +58,30 @@ predicate passes_open_files(Variable v, ControlFlowNode test, boolean sense) {
or
exists(UnaryExprNode n |
n = test and
n.getNode().getOp() instanceof Not |
n.getNode().getOp() instanceof Not
|
passes_open_files(v, n.getOperand(), sense.booleanNot())
)
}
/* Helper for `def_is_open` to give better join order */
private predicate passes_open_files(PyEdgeRefinement refinement) {
passes_open_files(refinement.getSourceVariable(), refinement.getPredecessor().getLastNode(), refinement.getSense())
passes_open_files(refinement.getSourceVariable(), refinement.getPredecessor().getLastNode(),
refinement.getSense())
}
/** Holds if `def` refers to a file opened at `open` */
predicate def_is_open(EssaDefinition def, ControlFlowNode open) {
expr_is_open(def.(AssignmentDefinition).getValue(), open)
or
exists(PyEdgeRefinement refinement |
refinement = def |
var_is_open(refinement.getInput(), open) and
exists(PyEdgeRefinement refinement | refinement = def |
var_is_open(refinement.getInput(), open) and
passes_open_files(refinement)
)
or
exists(PyNodeRefinement refinement |
refinement = def |
not closes_file(def) and not wraps_file(refinement.getDefiningNode(), refinement.getInput()) and
exists(PyNodeRefinement refinement | refinement = def |
not closes_file(def) and
not wraps_file(refinement.getDefiningNode(), refinement.getInput()) and
var_is_open(refinement.getInput(), open)
)
or
@@ -88,16 +91,15 @@ predicate def_is_open(EssaDefinition def, ControlFlowNode open) {
/** Holds if `call` closes a file */
predicate closes_file(EssaNodeRefinement call) {
closes_arg(call.(ArgumentRefinement).getDefiningNode(), call.getSourceVariable()) or
close_method_call(call.(MethodCallsiteRefinement).getCall(), call.getSourceVariable().(Variable).getAUse())
close_method_call(call.(MethodCallsiteRefinement).getCall(),
call.getSourceVariable().(Variable).getAUse())
}
/** Holds if `call` closes its argument, which is an open file referred to by `v` */
predicate closes_arg(CallNode call, Variable v) {
call.getAnArg() = v.getAUse() and
(
exists(FunctionObject close |
call = close.getACall() and function_closes_file(close)
)
exists(FunctionObject close | call = close.getACall() and function_closes_file(close))
or
call.getFunction().(NameNode).getId() = "close"
)
@@ -106,9 +108,7 @@ predicate closes_arg(CallNode call, Variable v) {
/** Holds if `call` closes its 'self' argument, which is an open file referred to by `v` */
predicate close_method_call(CallNode call, ControlFlowNode self) {
call.getFunction().(AttrNode).getObject() = self and
exists(FunctionObject close |
call = close.getACall() and function_closes_file(close)
)
exists(FunctionObject close | call = close.getACall() and function_closes_file(close))
or
call.getFunction().(AttrNode).getObject("close") = self
}
@@ -129,15 +129,13 @@ predicate function_should_close_parameter(Function func) {
predicate function_opens_file(FunctionObject f) {
f = Object::builtin("open")
or
exists(EssaVariable v, Return ret |
ret.getScope() = f.getFunction() |
ret.getValue().getAFlowNode() = v.getAUse() and
exists(EssaVariable v, Return ret | ret.getScope() = f.getFunction() |
ret.getValue().getAFlowNode() = v.getAUse() and
var_is_open(v, _)
)
or
exists(Return ret, FunctionObject callee |
ret.getScope() = f.getFunction() |
ret.getValue().getAFlowNode() = callee.getACall() and
exists(Return ret, FunctionObject callee | ret.getScope() = f.getFunction() |
ret.getValue().getAFlowNode() = callee.getACall() and
function_opens_file(callee)
)
}
@@ -145,7 +143,8 @@ predicate function_opens_file(FunctionObject f) {
predicate file_is_returned(EssaVariable v, ControlFlowNode open) {
exists(NameNode n, Return ret |
var_is_open(v, open) and
v.getAUse() = n |
v.getAUse() = n
|
ret.getValue() = n.getNode()
or
ret.getValue().(Tuple).getAnElt() = n.getNode()