Skip to content

Commit c8fc565

Browse files
Check for wrapper classes
1 parent ecb3050 commit c8fc565

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

python/ql/src/Resources/FileNotAlwaysClosedQuery.qll

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
/** Definitions for reasoning about whether files are closed. */
22

33
import python
4-
//import semmle.python.dataflow.DataFlow
4+
import semmle.python.dataflow.new.internal.DataFlowDispatch
55
import semmle.python.ApiGraphs
66

77
abstract class FileOpen extends DataFlow::CfgNode { }
88

99
class FileOpenCall extends FileOpen {
10-
FileOpenCall() { this = API::builtin("open").getACall() }
10+
FileOpenCall() { this = [API::builtin("open").getACall()] }
11+
}
12+
13+
class FileWrapperClassCall extends FileOpen, DataFlow::CallCfgNode {
14+
FileOpen wrapped;
15+
16+
FileWrapperClassCall() {
17+
wrapped = this.getArg(_).getALocalSource() and
18+
this.getFunction() = classTracker(_)
19+
}
20+
21+
FileOpen getWrapped() { result = wrapped }
1122
}
1223

13-
// todo: type tracking to find wrapping funcs
1424
abstract class FileClose extends DataFlow::CfgNode { }
1525

1626
class FileCloseCall extends FileClose {
1727
FileCloseCall() { exists(DataFlow::MethodCallNode mc | mc.calls(this, "close")) }
1828
}
1929

30+
class OsCloseCall extends FileClose {
31+
OsCloseCall() { this = API::moduleImport("os").getMember("close").getACall().getArg(0) }
32+
}
33+
2034
class WithStatement extends FileClose {
2135
WithStatement() { exists(With w | this.asExpr() = w.getContextExpr()) }
2236
}
@@ -34,6 +48,6 @@ predicate fileIsStoredInField(FileOpen fo) {
3448
predicate fileNotAlwaysClosed(FileOpen fo) {
3549
not fileIsClosed(fo) and
3650
not fileIsReturned(fo) and
37-
not fileIsStoredInField(fo)
38-
// TODO: exception cases
51+
not fileIsStoredInField(fo) and
52+
not exists(FileWrapperClassCall fwc | fo = fwc.getWrapped())
3953
}

0 commit comments

Comments
 (0)