Files
codeql/python/ql/src/Resources/FileNotAlwaysClosed.ql
2022-08-24 16:55:11 +01:00

75 lines
2.4 KiB
Plaintext

/**
* @name File is not always closed
* @description Opening a file without ensuring that it is always closed may cause resource leaks.
* @kind problem
* @tags efficiency
* correctness
* resources
* external/cwe/cwe-772
* @problem.severity warning
* @sub-severity high
* @precision medium
* @id py/file-not-closed
*/
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__`
*/
predicate opened_in_enter_closed_in_exit(ControlFlowNode open) {
file_not_closed_at_scope_exit(open) and
exists(FunctionValue entry, FunctionValue exit |
open.getScope() = entry.getScope() and
exists(ClassValue cls |
cls.declaredAttribute("__enter__") = entry and cls.declaredAttribute("__exit__") = exit
or
cls.declaredAttribute("__init__") = entry and cls.declaredAttribute("__del__") = exit
) and
exists(AttrNode attr_open, AttrNode attrclose |
attr_open.getScope() = entry.getScope() and
attrclose.getScope() = exit.getScope() and
expr_is_open(attr_open.(DefinitionNode).getValue(), open) and
attr_open.getName() = attrclose.getName() and
close_method_call(_, attrclose)
)
)
}
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())
}
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
not close_method_call(exit, v.getAUse().(NameNode)) and
var_is_open(v, open) and
v.getAUse() = exit.getAChild*()
)
}
/* 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."
)
select defn.getNode(), message