mirror of
https://github.com/github/codeql.git
synced 2025-12-24 20:56:33 +01:00
75 lines
2.4 KiB
Plaintext
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
|